Skip to main content

OCI OKE Service Account Token Mounting Should Be Restricted

More Info:

Service account tokens should be mounted into pods only when needed (automountServiceAccountToken=false by default). Auto-mounting tokens everywhere expands credential exposure if a pod is compromised.

Risk Level

Medium

Address

Compliance, Security

Compliance Standards

  • CIS OKE

Triage and Remediation

Remediation

Using Console

In OKE this is a Kubernetes‑level setting, but you can fix it entirely starting from the OCI Console by using the built‑in Cloud Shell and the OKE UI.

Below are concise, step‑by‑step instructions.


1. Open Your OKE Cluster from OCI Console

  1. Sign in to OCI Console.
  2. In the left menu: Developer Services → Kubernetes Clusters (OKE).
  3. Select the compartment that contains the cluster.
  4. Click on your cluster name.

2. Get kubectl Access from the Console (Cloud Shell)

  1. On the cluster details page, click Access Cluster.

  2. Choose Cloud Shell (recommended) so you run commands directly from the browser.

  3. In the panel that opens, click the button to Set Up Cluster Access (this usually runs the oci ce cluster create-kubeconfig… command for you).

  4. Verify connectivity:

    kubectl get nodes

3. Identify Service Accounts That Auto‑Mount Tokens

By default, service accounts auto‑mount tokens unless you disable it. Find which service accounts are doing that.

  1. List all service accounts in all namespaces:

    kubectl get sa -A
  2. For each namespace where you have workloads, check whether automountServiceAccountToken is set:

    kubectl get sa -n <NAMESPACE> -o yaml

    You will see either:

    • No automountServiceAccountToken field (means default true), or
    • automountServiceAccountToken: true, or
    • automountServiceAccountToken: false.

Your goal is to ensure it is false by default and only enabled where strictly needed.


4. Disable Token Auto‑Mounting at the Service Account Level

For each service account that should not have tokens automatically mounted:

  1. Edit the service account:

    kubectl edit sa <SERVICE_ACCOUNT_NAME> -n <NAMESPACE>
  2. In the YAML that opens, under metadata: (same level as secrets:), add or change:

    automountServiceAccountToken: false

    Example:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: my-app-sa
    namespace: my-app-namespace
    automountServiceAccountToken: false
  3. Save and exit (in vi, press Esc, then type :wq and press Enter).

Repeat for every service account that should not expose the token.


5. Override at Pod/Workload Level (Only Where Needed)

Some workloads may legitimately need the service account token. For those, keep the service account default as false, and enable auto‑mount only at the Pod / workload level.

5.1. Edit the Deployment/StatefulSet/Pod

  1. List deployments in a namespace:

    kubectl get deploy -n <NAMESPACE>
  2. Edit the workload that needs the token:

    kubectl edit deploy <DEPLOYMENT_NAME> -n <NAMESPACE>
  3. Under spec.template.spec, add:

    automountServiceAccountToken: true

    Example:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: my-api
    namespace: my-app-namespace
    spec:
    replicas: 2
    selector:
    matchLabels:
    app: my-api
    template:
    metadata:
    labels:
    app: my-api
    spec:
    serviceAccountName: my-api-sa
    automountServiceAccountToken: true
    containers:
    - name: api
    image: <IMAGE>
  4. Save and exit; Kubernetes will roll out updated pods.


6. Validate That Tokens Are No Longer Auto‑Mounted

  1. After changes roll out, check one of the pods:

    kubectl get pods -n <NAMESPACE>
    kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh
  2. Inside the container, confirm that the token file is absent for workloads that should not have it:

    ls /var/run/secrets/kubernetes.io/serviceaccount
    • If directory or token file is missing, auto‑mount is effectively disabled.
    • For workloads that should have it, it should still exist.

7. (Optional) Use the OKE Workloads UI Instead of kubectl edit

If you prefer not to edit YAML via terminal:

  1. In OCI Console → your OKE cluster → left menu Workloads.
  2. Choose the correct namespace.
  3. Click on a Deployment / StatefulSet / Pod.
  4. Use Edit YAML (or equivalent) and:
    • For ServiceAccount objects, add automountServiceAccountToken: false.
    • For Pod templates under workloads, add spec.automountServiceAccountToken: true only where needed.
  5. Save; OKE will apply the updated manifest.

Summary of the remediation:

  • Set automountServiceAccountToken: false on all service accounts by default.
  • Only enable automountServiceAccountToken: true at the pod/workload level where a token is strictly required.
  • All of this can be done starting from the OCI Console using the OKE page + Cloud Shell or the Workloads UI editor.
Using CLI

In OKE this is remediated with standard Kubernetes controls; OCI CLI is only used to get your kubeconfig so you can run kubectl against the cluster.

Below are the steps using OCI CLI + kubectl.


1. Get kubeconfig for your OKE cluster (via OCI CLI)

# Set env vars for convenience
COMPARTMENT_OCID="<your_compartment_ocid>"
CLUSTER_OCID="<your_oke_cluster_ocid>"

# Generate kubeconfig
oci ce cluster create-kubeconfig \
--cluster-id "$CLUSTER_OCID" \
--file "$HOME/.kube/oke-config" \
--region "<your_region>" \
--token-version 2.0.0 \
--kube-endpoint PUBLIC_ENDPOINT

# Point KUBECONFIG to that file (or merge it with your existing config)
export KUBECONFIG=$HOME/.kube/oke-config

Confirm access:

kubectl get nodes

2. Disable token auto-mounting at the ServiceAccount level

For each namespace, disable token auto-mounting on the default ServiceAccount (or any SA you use):

NAMESPACE="<your_namespace>"

kubectl patch serviceaccount default \
-n "$NAMESPACE" \
-p '{"automountServiceAccountToken": false}'

To verify:

kubectl get sa default -n "$NAMESPACE" -o yaml | grep -i automountServiceAccountToken -A1

Create new ServiceAccounts with token mounting disabled by default:

kubectl create serviceaccount restricted-sa -n "$NAMESPACE"

kubectl patch serviceaccount restricted-sa \
-n "$NAMESPACE" \
-p '{"automountServiceAccountToken": false}'

3. Disable token auto-mounting at the Pod/Deployment level

For existing Deployments/Pods that must not have tokens, explicitly set automountServiceAccountToken: false:

NAMESPACE="<your_namespace>"
DEPLOYMENT="<your_deployment_name>"

kubectl patch deployment "$DEPLOYMENT" \
-n "$NAMESPACE" \
-p '{"spec": {"template": {"spec": {"automountServiceAccountToken": false}}}}'

For raw Pods you can patch similarly:

POD="<your_pod_name>"

kubectl patch pod "$POD" \
-n "$NAMESPACE" \
-p '{"spec": {"automountServiceAccountToken": false}}'

When defining new workloads, include in the pod spec:

apiVersion: apps/v1
kind: Deployment
metadata:
name: example
namespace: your-namespace
spec:
template:
spec:
serviceAccountName: restricted-sa
automountServiceAccountToken: false
containers:
- name: app
image: your-image

4. Optionally audit current ServiceAccount token usage

List all ServiceAccounts and check for automountServiceAccountToken:

for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
echo "Namespace: $ns"
kubectl get sa -n "$ns" -o jsonpath='{range .items[*]}{.metadata.name}{" -> "}{.automountServiceAccountToken}{"\n"}{end}'
echo
done

Patch any with true or unset (Kubernetes default is true) as above.

Using Python

To restrict OKE service account token mounting you need to:

  1. Turn off automatic token mounting at the ServiceAccount level (cluster-wide or per namespace).
  2. Explicitly turn it on only for workloads that truly need it.
  3. Do this programmatically using the Kubernetes Python client.

Below is a concise, step‑by‑step approach and example Python code.


1. Prerequisites

  1. Ensure you can access your OKE cluster with kubectl:
    kubectl get nodes
  2. Install the Kubernetes Python client:
    pip install kubernetes
  3. Ensure your KUBECONFIG (or default ~/.kube/config) is set to the OKE cluster context you want to fix.

2. Hardening Strategy

Best practice:

  • Set automountServiceAccountToken: false on all ServiceAccounts by default, especially the default ServiceAccount in every namespace.
  • For Pods/Deployments that actually need the token (e.g., in‑cluster controllers, tools using Kubernetes API), explicitly set:
    spec:
    automountServiceAccountToken: true

We’ll focus here on disabling it cluster‑wide by default via Python.


3. Python Script: Disable Token Mounting for ServiceAccounts

This script:

  • Connects to the OKE cluster using your kubeconfig.
  • Iterates through all namespaces.
  • For each ServiceAccount (including default), sets automountServiceAccountToken: false unless you explicitly exempt it (via a skip list).
from kubernetes import client, config
from kubernetes.client.rest import ApiException

# Namespaces or service accounts you may want to skip (if they require token)
NAMESPACE_SKIP_LIST = [] # e.g. ["kube-system", "oracle-oci"]
SA_SKIP_LIST = [] # e.g. ["cluster-autoscaler"]

def main():
# Load kubeconfig from default location (~/.kube/config) or KUBECONFIG env
config.load_kube_config()

v1 = client.CoreV1Api()

try:
namespaces = v1.list_namespace().items
except ApiException as e:
print(f"Error listing namespaces: {e}")
return

for ns in namespaces:
ns_name = ns.metadata.name
if ns_name in NAMESPACE_SKIP_LIST:
print(f"Skipping namespace: {ns_name}")
continue

try:
sa_list = v1.list_namespaced_service_account(ns_name).items
except ApiException as e:
print(f"Error listing service accounts in {ns_name}: {e}")
continue

for sa in sa_list:
sa_name = sa.metadata.name

# Skip service accounts in SA_SKIP_LIST
if sa_name in SA_SKIP_LIST:
print(f"Skipping service account: {ns_name}/{sa_name}")
continue

# If already explicitly false, skip
if sa.automount_service_account_token is False:
print(f"No change (already false): {ns_name}/{sa_name}")
continue

# Patch the ServiceAccount to set automountServiceAccountToken: false
patch_body = {
"automountServiceAccountToken": False
}

try:
v1.patch_namespaced_service_account(
name=sa_name,
namespace=ns_name,
body=patch_body
)
print(f"Updated: {ns_name}/{sa_name} -> automountServiceAccountToken=False")
except ApiException as e:
print(f"Error patching SA {ns_name}/{sa_name}: {e}")

if __name__ == "__main__":
main()

Run it:

python harden_sa_tokens.py

4. (Optional) Explicitly Enable Token for Specific Workloads

For workloads that require the token, you can either:

  1. Set at Pod spec level (preferred):

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: needs-token
    namespace: my-namespace
    spec:
    template:
    spec:
    automountServiceAccountToken: true
    serviceAccountName: my-sa-that-needs-token
  2. Or adjust SA_SKIP_LIST in the Python script so that their ServiceAccount keeps automountServiceAccountToken default or true, then upgrade/redeploy them.


5. Integrating with OCI / OKE Automation (Optional)

If you want to run this as part of CI/CD or automation:

  • Package the script into a container image.
  • Run it as a Job or CronJob inside the OKE cluster with a ServiceAccount that has permissions to list/patch ServiceAccounts (rbac ClusterRole with get, list, patch on serviceaccounts).
  • Or run from an OCI DevOps pipeline or OCI Shell with kubeconfig pointing to the OKE cluster.

If you share how your OKE clusters are provisioned (Terraform, OCI Resource Manager, manual), I can add Terraform or pipeline examples to enforce this setting at creation time as well.

Using Terraform

This setting cannot be controlled on the oci_containerengine_cluster (Terraform oci_containerengine_cluster) resource: the OCI Container Engine for Kubernetes API does not expose a cluster‑level flag to set automountServiceAccountToken=false by default.

To remediate with Terraform you must manage this at the Kubernetes object level (not on the OKE cluster resource), for example by:

  • Defining kubernetes_service_account resources (via the hashicorp/kubernetes provider) with automount_service_account_token = false and only enabling it where explicitly required, or
  • Applying Kubernetes manifests (e.g., via kubectl, Helm, or Terraform kubernetes_manifest/helm_release) that set automountServiceAccountToken: false on ServiceAccounts/Pods, and/or admission policies that enforce this.

In the OCI Console, you would instead edit your Kubernetes ServiceAccounts (or controlling templates/Helm charts) to set automountServiceAccountToken: false by default and enable it only for workloads that truly need the token.