Accessing Kubernetes API from OpenShift Pods

How a pod running inside OpenShift can securely talk to the Kubernetes API using its mounted service account token, cluster CA certificate, and RBAC — with curl and Python examples.

By Network Nuts Team · Published 2026-07-14

Every pod running on OpenShift (or any Kubernetes cluster) can talk to the Kubernetes API server directly — no kubeconfig required. The cluster automatically gives each pod an identity through its service account, and everything needed to authenticate is mounted inside the container.

Where the credentials live

When a pod starts, Kubernetes mounts the service account token, the cluster CA certificate, and the current namespace at a well-known path:

/var/run/secrets/kubernetes.io/serviceaccount/token       # bearer token
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt      # cluster CA cert
/var/run/secrets/kubernetes.io/serviceaccount/namespace   # current namespace

Finding the API server

The API server is reachable from every pod through an in-cluster DNS name and injected environment variables:

# DNS name that always resolves to the API server
https://kubernetes.default.svc

# ...or build it from the injected environment variables
echo "https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}"

Calling the API with curl

Combine the token and CA certificate to make an authenticated, TLS-verified request from inside the pod:

APISERVER=https://kubernetes.default.svc
SA=/var/run/secrets/kubernetes.io/serviceaccount
TOKEN=$(cat $SA/token)
NAMESPACE=$(cat $SA/namespace)

curl --cacert $SA/ca.crt \
  --header "Authorization: Bearer $TOKEN" \
  -X GET "$APISERVER/api/v1/namespaces/$NAMESPACE/pods"

If you get a 403 Forbidden, authentication worked but the service account lacks permission — that is RBAC, covered next.

Granting permissions with RBAC

By default a pod's service account can do almost nothing. Grant exactly what it needs with a Role and a RoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: my-project
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: my-project
subjects:
  - kind: ServiceAccount
    name: default
    namespace: my-project
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

On OpenShift you can apply the same objects with oc apply -f role.yaml, or use the shortcuts:

oc create role pod-reader --verb=get,list,watch --resource=pods -n my-project
oc policy add-role-to-user pod-reader -z default --role-namespace=my-project -n my-project

Doing it from application code

Most languages ship an official Kubernetes client that auto-detects the in-cluster config — no manual token handling required. In Python:

from kubernetes import client, config

# Reads the mounted token + CA automatically when running inside a pod
config.load_incluster_config()

v1 = client.CoreV1Api()
for pod in v1.list_namespaced_pod("my-project").items:
    print(pod.metadata.name)

Best practices

  • Use a dedicated service account per workload instead of default, so you can scope permissions tightly.
  • Follow least privilege — grant only the verbs and resources the pod actually needs.
  • Never bake tokens into images or environment variables; read them from the mounted path so they rotate automatically.
  • Prefer Roles over ClusterRoles unless the workload genuinely needs cluster-wide access.

With the service account token, the cluster CA, and a small RBAC Role, any pod can query and manage Kubernetes resources securely — the foundation for operators, controllers, and in-cluster automation.