> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 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

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        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:

           ```bash theme={null}
           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:

           ```bash theme={null}
           kubectl get sa -A
           ```

        2. For each namespace where you have workloads, check whether `automountServiceAccountToken` is set:

           ```bash theme={null}
           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:

           ```bash theme={null}
           kubectl edit sa <SERVICE_ACCOUNT_NAME> -n <NAMESPACE>
           ```

        2. In the YAML that opens, under `metadata:` (same level as `secrets:`), add or change:

           ```yaml theme={null}
           automountServiceAccountToken: false
           ```

           Example:

           ```yaml theme={null}
           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:

           ```bash theme={null}
           kubectl get deploy -n <NAMESPACE>
           ```

        2. Edit the workload that needs the token:

           ```bash theme={null}
           kubectl edit deploy <DEPLOYMENT_NAME> -n <NAMESPACE>
           ```

        3. Under `spec.template.spec`, add:

           ```yaml theme={null}
           automountServiceAccountToken: true
           ```

           Example:

           ```yaml theme={null}
           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:

           ```bash theme={null}
           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:

           ```bash theme={null}
           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.
      </Accordion>

      <Accordion title="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)

        ```bash theme={null}
        # 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:

        ```bash theme={null}
        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):

        ```bash theme={null}
        NAMESPACE="<your_namespace>"

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

        To verify:

        ```bash theme={null}
        kubectl get sa default -n "$NAMESPACE" -o yaml | grep -i automountServiceAccountToken -A1
        ```

        Create new ServiceAccounts with token mounting disabled by default:

        ```bash theme={null}
        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`:

        ```bash theme={null}
        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:

        ```bash theme={null}
        POD="<your_pod_name>"

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

        When defining new workloads, include in the pod spec:

        ```yaml theme={null}
        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`:

        ```bash theme={null}
        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.
      </Accordion>

      <Accordion title="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`:
           ```bash theme={null}
           kubectl get nodes
           ```
        2. Install the Kubernetes Python client:
           ```bash theme={null}
           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:
          ```yaml theme={null}
          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).

        ```python theme={null}
        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:

        ```bash theme={null}
        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):

           ```yaml theme={null}
           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.
      </Accordion>

      <Accordion title="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.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
