Your pod won't start, and the logs show errors about missing secrets or permission denied when trying to access mounted secret files. Secrets are critical for storing sensitive data like passwords, tokens, and certificates, but when they fail to mount, your application can't access the credentials it needs to function.

Understanding Secret Mounting

Kubernetes secrets can be mounted as volumes or exposed as environment variables. When mounted as volumes, the kubelet retrieves the secret from the API server and writes it to a temporary filesystem on the node. The container then mounts this directory and can read the secret files.

Mount failures can occur at several stages: the secret doesn't exist, the secret reference is wrong, the pod doesn't have permission to access the secret, or there's a problem with the volume mount configuration.

Diagnosis Commands

Start by checking if the secret exists:

```bash # Check if secret exists in namespace kubectl get secrets -n namespace kubectl get secret secret-name -n namespace

# Describe secret to see its contents (base64 encoded) kubectl describe secret secret-name -n namespace

# Check secret across all namespaces kubectl get secrets -A | grep secret-name ```

Check the pod status and events:

```bash # Get pod status kubectl get pods -n namespace

# Describe the failing pod - look for volume mount errors kubectl describe pod pod-name -n namespace

# Check events for mount failures kubectl get events -n namespace --field-selector involvedObject.name=pod-name

# Look for specific error patterns kubectl describe pod pod-name -n namespace | grep -A 10 "MountVolume|secret" ```

Check how the pod references the secret:

```bash # Get pod's volume configuration kubectl get pod pod-name -n namespace -o yaml | grep -A 30 volumes

# Check secret volume reference kubectl get pod pod-name -n namespace -o jsonpath='{.spec.volumes[*].secret}' ```

Common Solutions

Solution 1: Create the Missing Secret

The secret might simply not exist:

```bash # Verify secret exists kubectl get secret my-secret -n namespace

# If it doesn't exist, create it kubectl create secret generic my-secret -n namespace --from-literal=username=admin --from-literal=password=secret123

# Create from file kubectl create secret generic my-secret -n namespace --from-file=ssh-privatekey=~/.ssh/id_rsa

# Create TLS secret kubectl create secret tls my-tls-secret -n namespace --cert=path/to/cert.pem --key=path/to/key.pem ```

Create from YAML:

yaml
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
  namespace: my-namespace
type: Opaque
data:
  username: YWRtaW4=  # base64 encoded
  password: c2VjcmV0MTIz
# Or use stringData for plaintext (will be encoded automatically)
stringData:
  username: admin
  password: secret123

Solution 2: Fix Secret Name Mismatch

The secret name in the pod spec must match exactly:

```bash # Check secret names available kubectl get secrets -n namespace

# Check what secret the pod expects kubectl get pod pod-name -n namespace -o jsonpath='{.spec.volumes[*].secret.secretName}' ```

Fix the secret reference:

```yaml # Pod with wrong secret name volumes: - name: secret-volume secret: secretName: wrong-secret-name # This doesn't exist

# Fix: Update to correct name volumes: - name: secret-volume secret: secretName: correct-secret-name # Matches existing secret ```

Solution 3: Fix Namespace Mismatch

Secrets are namespace-scoped. Pod and secret must be in the same namespace:

```bash # Check pod namespace kubectl get pod pod-name --all-namespaces | grep pod-name

# Check secret namespace kubectl get secret my-secret --all-namespaces ```

Copy secret to correct namespace:

bash
# Export secret and recreate in target namespace
kubectl get secret my-secret -n source-namespace -o yaml | sed 's/namespace: source-namespace/namespace: target-namespace/' | kubectl apply -f -

Solution 4: Fix Permission Denied Errors

RBAC might prevent the pod from accessing the secret:

```bash # Check service account used by pod kubectl get pod pod-name -n namespace -o jsonpath='{.spec.serviceAccountName}'

# Check RBAC roles kubectl get rolebindings -n namespace kubectl describe rolebinding rolebinding-name -n namespace

# Check if service account has secret access kubectl auth can-i get secrets -n namespace --as=system:serviceaccount:namespace:service-account-name ```

Create role and rolebinding:

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: secret-reader
  namespace: my-namespace
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    resourceNames: ["my-secret"]  # Optional: limit to specific secret
    verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-secrets-binding
  namespace: my-namespace
subjects:
  - kind: ServiceAccount
    name: my-service-account
    namespace: my-namespace
roleRef:
  kind: Role
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

Solution 5: Fix Secret Key Mismatch

The keys in the volume mount must match the secret's keys:

```bash # Check secret keys kubectl get secret my-secret -n namespace -o jsonpath='{.data}' | jq .

# Check what keys the pod expects kubectl get pod pod-name -n namespace -o jsonpath='{.spec.volumes[*].secret.items}' ```

Fix key mapping:

```yaml # Secret has keys: username, password # Pod volume configuration volumes: - name: secret-volume secret: secretName: my-secret items: - key: user # Wrong key name path: username.txt

# Fix: Use correct key volumes: - name: secret-volume secret: secretName: my-secret items: - key: username # Correct key path: username.txt ```

Solution 6: Check File Permissions

Mounted secrets have specific permissions that might cause issues:

bash
# Check default permission (0400 by default)
kubectl get pod pod-name -n namespace -o jsonpath='{.spec.volumes[*].secret.defaultMode}'

Adjust permissions:

yaml
volumes:
  - name: secret-volume
    secret:
      secretName: my-secret
      defaultMode: 0644  # More readable permission
      items:
        - key: username
          path: username.txt
          mode: 0644  # Per-item permission

Solution 7: Mark Secret as Optional

If the secret isn't always required, make it optional:

yaml
volumes:
  - name: secret-volume
    secret:
      secretName: optional-secret
      optional: true  # Pod will start without this secret

For environment variables:

yaml
env:
  - name: SECRET_VALUE
    valueFrom:
      secretKeyRef:
        name: optional-secret
        key: secret-key
        optional: true

Solution 8: Fix Immutable Field Issues

Secrets marked as immutable cannot be updated:

bash
# Check if secret is immutable
kubectl get secret my-secret -n namespace -o jsonpath='{.immutable}'

If you need to update an immutable secret, delete and recreate:

```bash # Save current secret kubectl get secret my-secret -n namespace -o yaml > secret-backup.yaml

# Delete and recreate kubectl delete secret my-secret -n namespace kubectl apply -f secret-backup.yaml ```

Solution 9: Debug Mount Issues

Check mount inside the pod:

```bash # Verify mount exists kubectl exec -it pod-name -n namespace -- ls -la /path/to/mount

# Check file contents kubectl exec -it pod-name -n namespace -- cat /path/to/mount/key-file

# Check permissions kubectl exec -it pod-name -n namespace -- stat /path/to/mount/key-file ```

Check kubelet logs on the node:

```bash # SSH to node ssh node-hostname

# Check kubelet logs for mount errors journalctl -u kubelet | grep -i "secret|MountVolume" ```

Verification

After fixing the issue:

```bash # Verify secret exists kubectl get secret my-secret -n namespace

# Verify pod starts successfully kubectl get pods -n namespace -l app=myapp

# Check secret is mounted kubectl exec -it pod-name -n namespace -- ls -la /etc/secrets/

# Verify secret content kubectl exec -it pod-name -n namespace -- cat /etc/secrets/username

# Check events for successful mount kubectl get events -n namespace --sort-by='.lastTimestamp' ```

Secret Mount Patterns

Basic Volume Mount

yaml
volumes:
  - name: secret-volume
    secret:
      secretName: my-secret
containers:
  - name: app
    volumeMounts:
      - name: secret-volume
        mountPath: /etc/secrets
        readOnly: true

Specific Keys Mount

yaml
volumes:
  - name: secret-volume
    secret:
      secretName: my-secret
      items:
        - key: username
          path: my-username
        - key: password
          path: my-password

Environment Variable

yaml
containers:
  - name: app
    env:
      - name: DB_PASSWORD
        valueFrom:
          secretKeyRef:
            name: my-secret
            key: password

All Keys as Environment Variables

yaml
containers:
  - name: app
    envFrom:
      - secretRef:
          name: my-secret

Secret Not Mounted Causes Summary

CauseCheck CommandSolution
Secret not createdkubectl get secretsCreate the secret
Wrong namespacekubectl get secrets -ACreate in correct namespace
Name mismatchkubectl describe podFix secret name reference
RBAC blockedkubectl auth can-iAdd role/rolebinding
Key mismatchkubectl get secret -o yamlFix key reference
Permission deniedCheck mount permissionsAdjust defaultMode
Immutable conflictkubectl get secret -o yamlDelete and recreate

Prevention Best Practices

Create secrets before pods that depend on them. Use consistent naming for secrets and references. Test secret access with kubectl auth can-i. Set appropriate file permissions for mounted secrets. Use external secret managers for production (Vault, External Secrets Operator). Rotate secrets regularly and update pods accordingly. Use immutable secrets when possible for stability.

Secret mount failures are usually straightforward - the secret either doesn't exist, is in the wrong namespace, or the pod doesn't have RBAC permission to read it. The kubectl describe pod command will show you exactly which secret is failing to mount and why.