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:
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: secret123Solution 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:
# 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:
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.ioSolution 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:
# Check default permission (0400 by default)
kubectl get pod pod-name -n namespace -o jsonpath='{.spec.volumes[*].secret.defaultMode}'Adjust permissions:
volumes:
- name: secret-volume
secret:
secretName: my-secret
defaultMode: 0644 # More readable permission
items:
- key: username
path: username.txt
mode: 0644 # Per-item permissionSolution 7: Mark Secret as Optional
If the secret isn't always required, make it optional:
volumes:
- name: secret-volume
secret:
secretName: optional-secret
optional: true # Pod will start without this secretFor environment variables:
env:
- name: SECRET_VALUE
valueFrom:
secretKeyRef:
name: optional-secret
key: secret-key
optional: trueSolution 8: Fix Immutable Field Issues
Secrets marked as immutable cannot be updated:
# 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
volumes:
- name: secret-volume
secret:
secretName: my-secret
containers:
- name: app
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: trueSpecific Keys Mount
volumes:
- name: secret-volume
secret:
secretName: my-secret
items:
- key: username
path: my-username
- key: password
path: my-passwordEnvironment Variable
containers:
- name: app
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-secret
key: passwordAll Keys as Environment Variables
containers:
- name: app
envFrom:
- secretRef:
name: my-secretSecret Not Mounted Causes Summary
| Cause | Check Command | Solution |
|---|---|---|
| Secret not created | kubectl get secrets | Create the secret |
| Wrong namespace | kubectl get secrets -A | Create in correct namespace |
| Name mismatch | kubectl describe pod | Fix secret name reference |
| RBAC blocked | kubectl auth can-i | Add role/rolebinding |
| Key mismatch | kubectl get secret -o yaml | Fix key reference |
| Permission denied | Check mount permissions | Adjust defaultMode |
| Immutable conflict | kubectl get secret -o yaml | Delete 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.