# kubectl proxy vs kubectl port-forward: Access Your Kubernetes Cluster Securely

When working with Kubernetes, developers often need a way to **access applications or services running inside the cluster** — without exposing them to the public internet.

## 1\. **Why Do We Need Local Access to Cluster Resources?**

In a secure Kubernetes architecture, most microservices run in an isolated internal network, meaning they are **not directly exposed** to the node's network or the public internet. This isolation is a **fundamental layer of security** and must be preserved, especially for high-security applications.

However, this strict isolation can make it difficult to troubleshoot internal connectivity and application behavior. The solution is to leverage Kubernetes-native tools to create secure, temporary tunnels that eliminate the need for external exposure.

The key advantage of using tools like `kubectl port-forward` and `kubectl proxy` is that they require no code modifications to the application container, preserving its immutability and reducing the risk of accidental exposure when debugging `highly secure applications`.

## 2\. Prerequisite: Establishing Cluster Trust

First verifies that you have the necessary **authentication (kubeconfig)** and **authorization (RBAC permissions)** required for accessing the cluster. You must be able to successfully run a basic command (e.g., kubectl get nodes) from the machine where you intend to run `kubectl port-forward` or `kubectl proxy`.

## 3\. What is `kubectl proxy`?

`kubectl proxy` acts as an HTTP reverse proxy between your local machine and the Kubernetes API server.  
It enables you to access any Kubernetes resource exposed by the API server — including **Pods**, **Services**, and other **API endpoints** — directly from your local host.

```plaintext
kubectl proxy
```

#### How it works

**1\. Local HTTP server start** – `kubectl proxy` starts a **local HTTP server** on your machine (by default at [http://localhost:8001](http://localhost:8001)).

**2\. Authentication with API server** – The proxy authenticates using your **kubeconfig credentials**, ensuring secure communication with the **Kubernetes API server**.

**3\. Request forwarding** – When you make a local HTTP request (e.g., [http://localhost:8001/api/](http://localhost:8001/api/)...), the proxy securely forwards it to the **Kubernetes API server** over **HTTPS**.

**4\. API server processing** – The **API server** receives the request, interacts with the appropriate Kubernetes resources (such as Pods, Services, Deployments or etc..), and prepares the response.

**5\. Response delivery** – The **proxy** sends the API server’s response back to your local machine, making it appear as if you’re directly interacting with the cluster’s REST API from [localhost](http://localhost).

**6.Traffic flow** – **Local machine → kubectl proxy (HTTP server) → API server → Kubernetes resource → API server → kubectl proxy → Local machine**

```plaintext
# You’ll see all the Pods in the default namespace directly fetched via the API server, not by connecting to the Pod network.
http://localhost:8001/api/v1/namespaces/default/pods

# To access a services
http://localhost:8001/api/v1/namespaces/<namespace>/services/<service-name>:<port-name>/proxy/
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
```

```plaintext
## Security aspects

# Most Explicit (Secure): Identical to the default behavior. Used to ensure the proxy is never accidentally exposed by other system configurations.
kubectl proxy --address=127.0.0.1 --accept-hosts='^127\.0\.0\.1$'

# Expose API to anyone who can reach your system.
kubectl proxy --address=0.0.0.0 --port=8001 

#Dangerous(Insecure): Binds to 0.0.0.0 (all network interfaces) and accepts requests from any host (^*\$).
kubectl proxy --address=0.0.0.0 --port=8001 --accept-hosts='^*$'
```

## 4\. What is `kubectl port-forward`?

`kubectl port-forward` establishes a **TCP tunnel** that allows you to connect directly from your local machine to a Pod’s or Service’s port.This method provides **application-specific access** for debugging or testing purposes, without exposing the application externally through a LoadBalancer or Ingress.  
You can perform port forwarding on **Pods**, **Services**, **Deployments**, **StatefulSets**, and **ReplicaSets**.

```plaintext
kubectl port-forward pod/<POD_NAME> <LOCAL_PORT>:<CONTAINER_PORT>
kubectl port-forward service/<SERVICE_NAME> <LOCAL_PORT>:<CONTAINER_PORT>
kubectl port-forward deployments/<DEPLOYMENT_NAME> <LOCAL_PORT>:<CONTAINER_PORT>
kubectl port-forward statefulsets/<STATEFULSET_NAME> <LOCAL_PORT>:<CONTAINER_PORT>
```

#### **How it works**

**1\. Connection to API server** – kubectl connects securely to the **Kubernetes API server** using your kubeconfig credentials, similar to how `kubectl proxy` operates.

**2\. Data stream to kubelet** – The **API server** identifies the node where the target Pod is running and securely streams the data to the **kubelet** on that node.

**3\. Pod connection and tunneling** – The **kubelet** opens a connection to the Pod’s specified port and tunnels the traffic back through the same API server channel to your local machine.

**4\. Local access established** – You can now access the Pod or Service locally through the forwarded port, without exposing it externally or modifying cluster networking.

**5.Traffic flow** – through this secure path: **Local machine → API server → kubelet → Pod.**

```plaintext
kubectl run flask-app --image=python:3.11 --port=5000
kubectl port-forward pod/flask-app 5000:5000
## Visit http://localhost:5000

# It takes random port on local machine
kubectl port-forward pod/my-pod :5000
kubectl port-forward --address 0.0.0.0 pod/my-pod 8888:5000

#To Run kubectl port forward command in background
kubectl port-forward pod/flask-app 5000:5000  &
```

## 5\. Security Note — Binding to `0.0.0.0`

By default, both `kubectl proxy` and `kubectl port-forward` bind to **127.0.0.1**, making them accessible **only from your local machine**.

If you manually bind them to **0.0.0.0**, they become accessible from **any network interface** — not just [localhost](http://localhost).  
While this can be helpful for remote debugging, it introduces a **major security risk**: Anyone on your network could potentially access your cluster through the open proxy or tunnel, especially if your **kubeconfig** remains active.

* **Best Practice:**
    
    * Keep the binding to **127.0.0.1** (default).
        
    * Only bind to **0.0.0.0** if you have:
        
        * Strong **network isolation** (e.g., VPN or private subnet).
            
        * Proper **authentication and authorization** controls in place.
            
        * Strict **firewall rules** limiting who can connect.
            

## 6\. Authentication & Authorization

| **Aspect** | `kubectl proxy` | `kubectl port-forward` |
| --- | --- | --- |
| **Authentication Type** | Every request goes through the **API server** | Authenticated **once when the tunnel is established** |
| **Credentials Used** | **Kubeconfig** (token / certificate / OIDC) | **Kubeconfig** (token / certificate / OIDC) |
| **RBAC Enforcement** | Enforced on **each API call** | Enforced **once at tunnel creation** |
| **Scope of Access** | **All cluster API resources** | **Specific Pod or Service** |
| **Security Strength** | Strong, per-request authentication | Strong, encrypted tunnel between local machine and Pod |
| **Stability / Reliability** | Very stable, persistent access | Can **break occasionally** due to network issues or Pod restarts |
| **Response Data** | Returns **raw HTTP/API responses** (JSON/YAML), e.g., resource lists, metrics, logs via API | Returns **TCP stream or application data** directly from the Pod (raw bytes, HTTP, database protocol, etc.) |

## 7\. When to Use Which

**For Local Testing and Debugging** – Use `kubectl proxy` or `port-forward` to test applications, APIs, or services running inside the cluster from your local machine without exposing them externally.

**For Accessing Cluster APIs (HTTP Traffic)** – Use `kubectl proxy` when you need **HTTP-based access** to Kubernetes resources, dashboards, or metrics APIs.

**For Application-Specific Access (TCP Traffic)** – Use `kubectl port-forward` to connect directly to a Pod or Service for **TCP-based access**, such as web apps, databases, or message queues like Kafka, in a development or testing environment.

**For Short-Lived Connections** – Ideal for temporary operations like inspecting logs, running queries, or testing functionality, where permanent exposure is not required.

**For Secure Local Access** – Both commands keep your traffic encrypted and access restricted to your kubeconfig permissions, making them safe for local development.

## 8\. When not to Use

**In Production** – These are temporary connections that break when the command or terminal is closed. Use Ingress, LoadBalancer, or proper service exposure instead.

**For Automation or CI/CD** – Port-forwarding can hang or fail randomly. Use ClusterIP or internal services for reliable automation.

**For Heavy Traffic** – All traffic passes through the API server, which can cause latency and performance bottlenecks. Use proper network routing or service exposure instead.

**For Long-Running Streams** – Database or message queue connections, such as PostgreSQL or Kafka, can drop easily. Use a VPN, Bastion host, or persistent service exposure instead.

**On Shared Machines** – Anyone with access to the machine could reach your forwarded ports. Keep bindings local (127.0.0.1) and secure your environment.

**Without Access Control** – Running with admin kubeconfig may expose sensitive APIs. Enforce RBAC, limit privileges, and enable audit logging.

## 💡 Question of the Day:

If you had to securely expose a Kubernetes service for your team without using Ingress or LoadBalancer, what would be your preferred approach and why?

> ### Secure, local, temporary – debug smart, expose smart.
