From a user level, net-forward helps you create a forwarding proxy from your machine to an arbitrary IP and port that’s accessible in the cluster. For example if you wanted to connect to another Pod’s service located at 10.0.0.5 on port 80, it would look like this:
kubectl net_forward -i 10.0.0.5 -p 80
You may say this looks a lot like
kubectl port-forward, and you’d be right,
but there’s a couple of differences that are important.
port-forwardonly allows you to forward to other Pods/Services in a cluster: This makes sense when you want to play around with other k8s objects but not when you’re debugging or testing other scenarios.
net-forwarddoesn’t require that you have permission to query other namespaces and services. Unlike
port-forwardwhich assume that you’re a privileged user or cluster-admin,
net-forwarddoesn’t do any extra lookup of the service object’s information. This means that if you have a restricted account – such as a compromised service account token or a user account bound to a single namespace – you’ll still be able to make the requests using
I’ll likely show this in more detail at my Shmoocon talk next week but here’s a scenario that I’ve run into that makes this useful to me. Here’s a diagram of a cluster:
During a pentest, imagine you’ve compromised the a Pod and you’ve taken over the service account token inside the “secure” namespace shown above. From there you find that you’re able to perform any API function in the context of that namespace but you’re blocked from doing anything in other namespaces such as “default”. But there are no network policies or callico or istio that might restrict networking between those Pods. So if you were to find another service such as the “Webadmin” Pod in the “Default” namespace, you’d like to be able to connect into it.
port-forward you’d want to execute a command like
kubectl port-forward -n default my-pod-name-xxxxx-xxxxxx 8080 which is the Pod name and the port you
want to connect into. That doesn’t work here.
In this scenario, you don’t have the name of the Pod, you only have the IP
address and port you want to connect to which might be 10.0.0.5:5000. This is
net-forward becomes useful because there are no constraints on what you
can connect in with.
You could simply run
kubectl net_forward -i 10.0.0.5 -p 5000 and you’ll have a
listener created for you on your local machine on port 9999 and you’re now able
to target this new service with all your favorite tools from the comfort of your
personal laptop that has all your favorite tools on it.
I can make it even simplier. What if you wanted to make a direct connection to your cloud provider’s metadata endpoint. We know that this is a juicy location for pentesters to target because in some cases it lets you access sensitive information such as cloud credentials.
There’s currently no way to do it with
kubectl port-forward but you can do it
$ kubectl net_forward -i 169.254.169.254 -p 80`
This gives you direct access to the metadata endpoint accessible to the cluster you’ve compromised.
This tool works in the same way as
port-forward which creates a socat Pod
and tells it to redirect to whatever service you tell it. It is equivilent of
running the following:
$ kubectl run -n secure --restart=Never \ --image=alpine/socat socat1 \ -- -d -d tcp-listen:9999,fork,reuseaddr tcp-connect:10.0.0.5:5000 $ kubectl port-forward -n secure socat1 9999
This is just a simple script that would make me more comfortable going through the Krew review process. I’m definitely pushing the boundaries about what’s worthwhile to include within Krew. Krew is designed for cluster operators to debug and mess around with their cluster. I have different operating constraints. The Krew folks were really helpful and provided questions that I replied to about the intention of the plugin. I plan to put more tools into Krew with kind of specific operating constraints in the future so I hope I don’t piss any of them off.
You can install net-forward today with:
$ kubectl krew install net-forward