A simple tinyproxy blueprint to forward HTTP(S) traffic from apps running on Kubernetes. This kind of proxy is also called an HTTP CONNECT proxy, or just an HTTP(s) forward proxy. It does not intercept the traffic and instead sets up a tunnel between the client and the target.
-
Man-in-the-middle TLS inspection proxy - useful for deep packet inspection and reverse engineering HTTPS encrypted traffic
-
mTLS Proxy with client credentials - useful in zero-trust settings
Run the following:
# (Optional) create a local cluster
kind create cluster --name test-proxy
git clone https://github.com/ofirc/k8s-http-proxy/
cd k8s-http-proxy
kubectl apply -f deploy/
kubectl wait --for=condition=Available deployment/proxy-server --timeout=150s
kubectl run curl --image=curlimages/curl -- sleep infinity
kubectl wait --for=condition=Ready pod/curl --timeout=150s
kubectl exec -it curl -- sh
export https_proxy=http://proxy-server.default.svc:8888
curl https://example.com
To ensure the traffic went through the proxy:
kubectl logs -l app=proxy-server
Example output:
$ kubectl logs -l app=proxy-server
INFO Mar 28 22:03:56.669 [1]: Setting the various signals.
INFO Mar 28 22:03:56.669 [1]: Starting main loop. Accepting connections.
CONNECT Mar 28 22:05:34.891 [1]: Connect (file descriptor 7): 10.244.0.6
CONNECT Mar 28 22:05:34.893 [1]: Request (file descriptor 7): CONNECT example.com:443 HTTP/1.1
INFO Mar 28 22:05:34.895 [1]: No upstream proxy for example.com
INFO Mar 28 22:05:34.895 [1]: opensock: opening connection to example.com:443
INFO Mar 28 22:05:34.915 [1]: opensock: getaddrinfo returned for example.com:443
CONNECT Mar 28 22:05:35.129 [1]: Established connection to host "example.com" using file descriptor 8.
INFO Mar 28 22:05:35.129 [1]: Not sending client headers to remote machine
INFO Mar 28 22:05:35.618 [1]: Closed connection between local client (fd:7) and remote client (fd:8)
$
Optional, tear down the cluster:
kind delete cluster --name test-proxy
In enterprise settings, all outbound (egress) traffic typically goes through a proxy server of some kind. As a developer / product owner, your app is required to go through this proxy for communicating with remote targets such as your SaaS backends. This is done for various reasons, e.g. anonymizing, caching, compliance, governance, etc.
What could possibly go wrong 🤔?
- Debugging - The app fails to communicate through the forward HTTP proxy server Is the problem in the HTTP proxy server? Is it a misconfigured client? How do I debug it?
- Developing - I am a developer with not much of an experience with proxies in Kuberntes I was assigned a task to support proxies for my app but I'm not sure where to start.
Famous last words: big deal, I'll just setup a proxy!
But:
Also, LLMs may occassionally emit interesting configurations for proxies in Kubernetes.
Finally, incumbents like OSS Squid proxy might be overwhelming and overkill for beginners, and paying for a managed cloud proxy is out of the question.
That's where this repo shines, providing you with a simple reference proxy you can run test it. Jump to TL;DR for more information.
- kubectl - Kubernetes command-line tool
- git - Version control system
- kind (optional) - Tool for running local Kubernetes clusters
Step 0: (Optional) create a local cluster
kind create cluster --name test-proxy
Step 1: clone this repository
git clone https://github.com/ofirc/k8s-http-proxy/
cd k8s-http-proxy
Step 2: deploy the tinyproxy deployment
kubectl apply -f deploy/
kubectl wait --for=condition=Available deployment/proxy-server --timeout=150s
Step 3: spin up an ephemeral Pod for experimenting
kubectl run curl --image=curlimages/curl -- sleep infinity
kubectl wait --for=condition=Ready pod/curl --timeout=150s
Step 4: verify the running Pods If all went well, this is what you should see:
$ kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/curl 1/1 Running 0 18s
pod/proxy-server-xxxxxxxxx-xxxxx 1/1 Running 0 9m2s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18d
service/proxy-server ClusterIP 10.98.161.180 <none> 8888/TCP 8m11s
$
Execute into the ephemeral curl Pod:
kubectl exec -it curl -- sh
Set the proxy environment variable:
export https_proxy=http://proxy-server.default.svc:8888
Trigger an HTTPS request:
curl https://example.com
Check the proxy server logs:
kubectl logs -l app=proxy-server
Example output:
$ kubectl logs -l app=proxy-server
INFO Mar 28 22:03:56.669 [1]: Setting the various signals.
INFO Mar 28 22:03:56.669 [1]: Starting main loop. Accepting connections.
CONNECT Mar 28 22:05:34.891 [1]: Connect (file descriptor 7): 10.244.0.6
CONNECT Mar 28 22:05:34.893 [1]: Request (file descriptor 7): CONNECT example.com:443 HTTP/1.1
INFO Mar 28 22:05:34.895 [1]: No upstream proxy for example.com
INFO Mar 28 22:05:34.895 [1]: opensock: opening connection to example.com:443
INFO Mar 28 22:05:34.915 [1]: opensock: getaddrinfo returned for example.com:443
CONNECT Mar 28 22:05:35.129 [1]: Established connection to host "example.com" using file descriptor 8.
INFO Mar 28 22:05:35.129 [1]: Not sending client headers to remote machine
INFO Mar 28 22:05:35.618 [1]: Closed connection between local client (fd:7) and remote client (fd:8)
$
kubectl delete -f deploy/
kubectl delete pod curl --force
Optional, tear down the cluster:
kind delete cluster --name test-proxy
- A Kubernetes Deployment of
proxy-server
with one replica running tinyproxy - A Kubernetes Service called
proxy-server
- An ephemeral Pod running the
curlimages/curl
image, used for testing
- Port 8888 for the tinyproxy port