HackTricks
Searchโ€ฆ
๐Ÿ‘ฝ
Network Services Pentesting
Exposing Services in Kubernetes
Support HackTricks and get benefits!
There are different ways to expose services in Kubernetes so both internal endpoints and external endpoints can access them. This Kubernetes configuration is pretty critical as the administrator could give access to attackers to services they shouldn't be able to access.

Automatic Enumeration

Before starting enumerating the ways K8s offers tot expose services to the public, know that if you can list namespaces, services and ingresses, you can everything exposed to the public with:
1
kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do
2
echo "Namespace: $ns"
3
kubectl get service -n "$ns"
4
kubectl get ingress -n "$ns"
5
echo "=============================================="
6
echo ""
7
echo ""
8
done | grep -v "ClusterIP"
9
# Remove the last '| grep -v "ClusterIP"' to see also type ClusterIP
Copied!

ClusterIP

A ClusterIP service is the default Kubernetes service. It gives you a service inside your cluster that other apps inside your cluster can access. There is no external access.
However, this can be accessed using the Kubernetes Proxy:
1
kubectl proxy --port=8080
Copied!
Now, you can navigate through the Kubernetes API to access services using this scheme:
http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/
For example you could use the following URL:
http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/
to access this service:
1
apiVersion: v1
2
kind: Service
3
metadata:
4
name: my-internal-service
5
spec:
6
selector:
7
app: my-app
8
type: ClusterIP
9
ports:
10
- name: http
11
port: 80
12
targetPort: 80
13
protocol: TCP
Copied!
This method requires you to run kubectl as an authenticated user.

NodePort

NodePort opens a specific port on all the Nodes (the VMs), and any traffic that is sent to this port is forwarded to the service. This is a really bad option usually.
An example of NodePort specification:
1
apiVersion: v1
2
kind: Service
3
metadata:
4
name: my-nodeport-service
5
spec:
6
selector:
7
app: my-app
8
type: NodePort
9
ports:
10
- name: http
11
port: 80
12
targetPort: 80
13
nodePort: 30036
14
protocol: TCP
Copied!
If you don't specify the nodePort in the yaml (it's the port that will be opened) a port in the range 30000โ€“32767 will be used.

LoadBalancer

Exposes the Service externally using a cloud provider's load balancer. On GKE, this will spin up a Network Load Balancer that will give you a single IP address that will forward all traffic to your service.
You have to pay for a LoadBalancer per exposed service, which can get expensive.

ExternalName

Services of type ExternalName map a Service to a DNS name, not to a typical selector such as my-service or cassandra. You specify these Services with the spec.externalName parameter.
This Service definition, for example, maps the my-service Service in the prod namespace to my.database.example.com:
1
apiVersion: v1
2
kind: Service
3
metadata:
4
name: my-service
5
namespace: prod
6
spec:
7
type: ExternalName
8
externalName: my.database.example.com
Copied!
When looking up the host my-service.prod.svc.cluster.local, the cluster DNS Service returns a CNAME record with the value my.database.example.com. Accessing my-service works in the same way as other Services but with the crucial difference that redirection happens at the DNS level rather than via proxying or forwarding.

External IPs

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.
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)
1
apiVersion: v1
2
kind: Service
3
metadata:
4
name: my-service
5
spec:
6
selector:
7
app: MyApp
8
ports:
9
- name: http
10
protocol: TCP
11
port: 80
12
targetPort: 9376
13
externalIPs:
14
- 80.11.12.10
Copied!

Ingress

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.
You can do a lot of different things with an Ingress, and there are many types of Ingress controllers that have different capabilities.
The default GKE ingress controller will spin up a HTTP(S) Load Balancer for you. This will let you do both path based and subdomain based routing to backend services. For example, you can send everything on foo.yourdomain.com to the foo service, and everything under the yourdomain.com/bar/ path to the bar service.
The YAML for a Ingress object on GKE with a L7 HTTP Load Balancer might look like this:
1
apiVersion: extensions/v1beta1
2
kind: Ingress
3
metadata:
4
name: my-ingress
5
spec:
6
backend:
7
serviceName: other
8
servicePort: 8080
9
rules:
10
- host: foo.mydomain.com
11
http:
12
paths:
13
- backend:
14
serviceName: foo
15
servicePort: 8080
16
- host: mydomain.com
17
http:
18
paths:
19
- path: /bar/*
20
backend:
21
serviceName: bar
22
servicePort: 8080
Copied!

References

Support HackTricks and get benefits!