Browsing websites through a Kubernetes pod

Marius
5 min readFeb 25, 2024

--

Kubernetes clusters are typically very closed down and I became curious if it is possible to browse any URL as if I was inside the cluster as a pod, using the clusters egress, should be possible, right? 🤔

The only requirement is that you have access to launch a pod in the Kubernetes cluster, which you will use as the hub, and also be able to run kubectl port-forward to that pod, let’s see how it’s done!

Let’s use a simple webpage such as ident.me and ifconfig.me which displays your IP-address when you visit it. This can be used to verify if our traffic is indeed coming from the Kubernetes pod. We will begin with ident.me, you will understand why later.

We are going to use socat which is a unix bidirectional byte-stream relay tool, you can read the manual here: https://linux.die.net/man/1/socat.

There is already an official alpine image with socat installed, let’s use that! All we need to do is to set up a port in the Pod to listen on, below it is 8080, and then we tell socat to forward all that traffic to and from ident.me, and finally we specify the port 80 to imply we want to use http.

kubectl run -it --rm --image alpine/socat alpine \
-- "TCP-LISTEN:8080,fork" "TCP:ident.me:80"

Now we can set up a tunnel our traffic through this pod on port 8080

kubectl port-forward alpine 8080:8080

If we now run the following command, we will se the result as if the traffic comes from our pod instead of from our computer. (The following is an AWS IP, my local IP is a different address)

It works, yay! 🎉
curl localhost:8080

We can even try it out in the browser:

Great! If we now close the existing connections and only change the domain to the slightly more popular site ifconfig.me we will notice things:

kubectl run -it --rm --image alpine/socat alpine \
-- "TCP-LISTEN:8080,fork" "TCP:ifconfig.me:80"

and again

kubectl port-forward alpine 8080:8080

Why do we get this response only when using the proxy?

It works on my machine

Well, you might be lucky on some websites, but often websites utilize a common security protection that will stop us from performing Cross-Site Request Forgery (CSRF). Each time you visit a website using your browser, it will attach a request header Host and set it to the url you are trying to reach, in our case localhost:8080. When it arrives at the loadbalancer in front of the server it will compare if this looks correct, and since it is not equal to ifconfig.me it will deny the request. You can read more here.

A common exploit websites want to protect from is when embedded javascript on a malicious website sends requests to a legitimate website. If you are already logged in to that legitimate website from before, the browser will include cookies, meaning that you are already authenticated, and the javascript will have full access to your account. By using CSRF protection this can be prevented. Seems like ifconfig.me have thought about security! 🫡

There are ways around this, either setting up a man-in-the-middle (MITM) proxy that will set the header for you, or you can spoof the header yourself using curl. Here we can see the difference:

But what about the browser, how can we modify its header?

Well, the idea is that you shouldn’t, but there exists plugins that can modify the browsers request headers, here’s one that was Featured on the Chrome store:

But as always, stay safe and never trust blindly on the internet, it has some disappointed reviews:

A better way, since you are doing this intentionally, can be to temporarily modify the hosts file. This requires no additional software to be installed. Use your favourite editor and add the following line at the bottom; remember you need to use sudo as it is protected

sudo vim /etc/hosts

Add this line:

127.0.0.1       ifconfig.me

This works like a DNS-entry, so every time you want to visit ifconfig.me it will not look up the real IP-address, but instead send it immediately to your local 127.0.0.1 address.

Additionally, we cannot use the local port 8080 as this would also be part of the Host-header. Anytime port 80 (or 443) is used, the browser will omit the port in the header.

As you might be aware however, the vast majority of http-traffic is force-redirecting to https, so continuing to experiment with http is not very usable. From now, let’s only consider https traffic.

Luckily socat will gladly forward encrypted traffic as well, simply set the destination port to 443. That means we can just modify that address to anything, right?! Let’s try!

Working solution

kubectl run -it --rm --image alpine/socat alpine \
-- "TCP-LISTEN:8080,fork" "TCP:ifconfig.me:443"

and again (with sudo to bind to local port 443):

sudo kubectl port-forward alpine 443:8080

We can now securely visit the website in the browser using https through our Kubernetes pod´s egress and get that IP.

You can change ifconfig.me to any domain you want to use, as long as you also change in both (socat-command and /etc/hosts-file).

Note!

Don’t forget to clean up by removing your entry in your /etc/hosts file!

--

--

No responses yet