> ## 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.

# Prefer Using Secrets As Files Over Secrets As Environment Variables

### More Info:

Secrets exposed as environment variables are more easily leaked through logs, child processes, and crash dumps. Mount secrets as files instead and read them from the filesystem.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* CIS OKE

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **List pods that reference Secrets in env/envFrom**
           * On any machine with kubectl access:
             ```bash theme={null}
             kubectl get pods -A -o json \
               | jq -r '.items[]
                 | select(
                     ([.spec.containers[], (.spec.initContainers // [])[]]
                       | map(
                           (.env // [])[]?.valueFrom.secretKeyRef? // empty
                           + (.envFrom // [])[]?.secretRef? // empty
                         )
                       | length) > 0
                   )
                 | "\(.metadata.namespace) \(.metadata.name)"'
             ```

        2. **Inspect how each affected pod uses Secrets**
           * For each `<namespace> <pod>` from step 1, get its full spec:
             ```bash theme={null}
             kubectl get pod <pod-name> -n <namespace> -o yaml
             ```
           * Review for `env:` and `envFrom:` entries with `secretKeyRef` / `secretRef`, and check whether there is already an alternative `volume` / `volumeMount` using the same Secret.

        3. **Review application code / startup scripts for each pod**
           * For each affected workload (Deployment/StatefulSet/Job, etc.), identify the image and owning controller:
             ```bash theme={null}
             kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.metadata.ownerReferences[0].kind}{" "}{.metadata.ownerReferences[0].name}{" "}{.spec.containers[*].image}{"\n"}'
             ```
           * Using your source control or image documentation, determine whether the application reads these secret values from environment variables, or can instead read from files (e.g., configurable paths, options, or library support).

        4. **Decide and implement code/config changes to use mounted files**
           * If the application can be changed, update code or configuration to read secrets from known filesystem paths (for example `/var/run/secrets/<name>`), and rebuild/publish images as needed.
           * If the application cannot reasonably be changed (legacy, third‑party, or breaks existing integrations), document the exception and rationale for continuing to use environment variables.

        5. **Refactor pod specs to mount Secrets as files instead of env vars**
           * For each controller owning affected pods, edit its manifest to:
             * Add a Secret volume and mount path. Example (edit with `kubectl edit` or your GitOps/IaC):
               ```yaml theme={null}
               spec:
                 template:
                   spec:
                     volumes:
                     - name: app-secret
                       secret:
                         secretName: my-secret
                     containers:
                     - name: app
                       volumeMounts:
                       - name: app-secret
                         mountPath: /var/run/secrets/my-secret
                         readOnly: true
                       # Remove or minimize:
                       # env:
                       # - name: SECRET_VALUE
                       #   valueFrom:
                       #     secretKeyRef:
                       #       name: my-secret
                       #       key: key1
               ```
           * Apply updated manifests with `kubectl apply -f <file.yaml>` from any machine with kubectl access.

        6. **Verify remaining use of Secrets in environment variables**
           * After rollouts complete, re-run the evidence-gathering query:
             ```bash theme={null}
             kubectl get pods -A -o json \
               | jq -r '.items[]
                 | select(
                     ([.spec.containers[], (.spec.initContainers // [])[]]
                       | map(
                           (.env // [])[]?.valueFrom.secretKeyRef? // empty
                           + (.envFrom // [])[]?.secretRef? // empty
                         )
                       | length) > 0
                   )
                 | "\(.metadata.namespace) \(.metadata.name)"'
             ```
           * Confirm that only pods with documented exceptions still appear, and that the rest use mounted Secret volumes instead.
      </Accordion>

      <Accordion title="Using kubectl">
        ### Using kubectl

        Run these commands from any machine with `kubectl` access.

        #### 1. List pods that use `env` or `envFrom` (cluster-wide)

        ```bash theme={null}
        kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{range .spec.containers[*]}{"  container: "}{.name}{"\n"}{"    env: "}{range .env[*]}{.name}{"="}{@}{"\n"}{end}{"    envFrom: "}{range .envFrom[*]}{@}{"\n"}{end}{"\n"}{end}{"\n"}{end}'
        ```

        Problem indication:

        * Any `env` entry that includes `valueFrom.secretKeyRef`.
        * Any `envFrom` entry that includes `secretRef`.

        These are containers consuming secrets via environment variables.

        #### 2. Inspect a specific pod’s environment for secret usage

        Replace `<namespace>` and `<pod>`:

        ```bash theme={null}
        kubectl get pod <pod> -n <namespace> -o yaml
        ```

        Check under `spec.containers[].env` and `spec.containers[].envFrom`:

        * `env[].valueFrom.secretKeyRef` → secret as environment variable (problem).
        * `envFrom[].secretRef` → entire secret as environment variables (problem).

        Also confirm whether the same pod (or deployment) already mounts the secret as a volume under `spec.volumes` and `spec.containers[].volumeMounts`; if so, environment use is usually unnecessary.

        #### 3. Identify higher-level controllers using secrets as env

        To fix properly, you must usually modify the controller (Deployment, StatefulSet, etc.), not the Pod.

        Find the owning controller of a pod:

        ```bash theme={null}
        kubectl get pod <pod> -n <namespace> -o jsonpath='{.metadata.ownerReferences}'
        ```

        Then inspect the controller spec:

        ```bash theme={null}
        kubectl get deployment <name> -n <namespace> -o yaml
        kubectl get statefulset <name> -n <namespace> -o yaml
        kubectl get daemonset <name> -n <namespace> -o yaml
        ```

        Problem indication in these specs:

        * Any `env[].valueFrom.secretKeyRef` under `spec.template.spec.containers[]`.
        * Any `envFrom[].secretRef` under `spec.template.spec.containers[]`.

        #### 4. Confirm where secrets are used as volumes (for comparison)

        ```bash theme={null}
        kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{range .spec.volumes[*]}{"  volume: "}{.name}{" "}{@}{"\n"}{end}{"\n"}{end}'
        ```

        Healthy indication:

        * Secrets appear under `spec.volumes[].secret.secretName`.
        * Corresponding `spec.containers[].volumeMounts[].name` reference those secret volumes.
        * No (or minimized) use of the same secrets via `env`/`envFrom`.

        Human review required:

        * Decide, per application, whether you can change the code/config to read from mounted files instead of environment variables.
        * Plan and implement changes in manifests and application code; there is no safe automated `kubectl` transformation.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Report pods that use Kubernetes Secrets as environment variables
        # Run on: any machine with kubectl access and current context set

        set -euo pipefail

        # Header
        echo "NAMESPACE,POD,CONTAINER,ENV_TYPE,REF_KIND,REF_NAME,ENV_VAR"

        # Function to process a pod JSON and emit CSV lines
        kubectl get pods --all-namespaces -o json \
        | jq -r '
          .items[]
          | . as $pod
          | ($pod.metadata.namespace // "default") as $ns
          | ($pod.metadata.name) as $podname
          | [
              # regular containers
              ($pod.spec.containers[]? | {type: "container", name, env, envFrom}),
              # init containers
              ($pod.spec.initContainers[]? | {type: "initContainer", name, env, envFrom})
            ]?
          | select(. != null)
          | . as $c
          |
          # 1) env vars directly from secretKeyRef
          (
            $c.env[]?
            | select(.valueFrom.secretKeyRef != null)
            | [
                $ns,
                $podname,
                $c.name,
                ($c.type),
                "SecretKeyRef",
                .valueFrom.secretKeyRef.name,
                .name
              ]
            | @csv
          ),
          # 2) envFrom entries from Secret
          (
            $c.envFrom[]?
            | select(.secretRef != null)
            | [
                $ns,
                $podname,
                $c.name,
                ($c.type),
                "SecretRef",
                .secretRef.name,
                "*"
              ]
            | @csv
          )
        '

        cat <<'EOF'

        Explanation:
        - Any CSV line in the output indicates a pod/container that exposes a Secret as environment variables.
        - Columns:
          NAMESPACE   : Namespace of the pod
          POD         : Pod name
          CONTAINER   : Container or initContainer name
          ENV_TYPE    : "container" or "initContainer"
          REF_KIND    : "SecretKeyRef" = individual env var from secret; "SecretRef" = all keys from secret via envFrom
          REF_NAME    : Name of the Secret object
          ENV_VAR     : Specific env var name, or "*" when all keys are imported via envFrom

        What indicates a problem:
        - Any non-empty output means there are pods using Secrets as environment variables.
        - Focus review on these lines and consider refactoring those workloads to mount the Secret as a volume
          and read it from the filesystem instead of via environment variables.
        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
