Kubernetes PKI Certificate File Permissions Should Be 644
More Info:
Verifies that Kubernetes PKI certificate files have permissions of 644 or more restrictive to protect the clusters public certificates from tampering.
Risk Level
Medium
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
- On every control plane node, list current permissions for all PKI certificate files and review them for unexpected entries or ownership before changing anything:
sudo find /etc/kubernetes/pki/ -name '*.crt' -exec ls -l {} \;
- Still on each control plane node, back up the PKI directory (for recovery if needed):
sudo cp -a /etc/kubernetes/pki /etc/kubernetes/pki.backup.$(date +%F-%H%M%S)
- On each control plane node, set certificate file permissions to
644(owner read/write, group and others read-only), which is “644 or more restrictive”:
sudo chmod -R 644 /etc/kubernetes/pki/*.crt
- On each control plane node, ensure the certificate files are owned by the expected Kubernetes user and group (commonly
root:root); adjust if needed based on your environment’s standard:
sudo chown root:root /etc/kubernetes/pki/*.crt
- If your environment requires stricter permissions (for example, no world-read), you may optionally further restrict them, but only after confirming that all Kubernetes components that need to read these certificates will still have access:
# Example of stricter permissions, if validated as safe for your setup:
# sudo chmod -R 640 /etc/kubernetes/pki/*.crt
- Verify on each control plane node that all
.crtfiles now have permissions644or more restrictive (e.g., 640, 600):
sudo find /etc/kubernetes/pki/ -name '*.crt' | xargs stat -c 'permissions=%a %n'
Using kubectl
kubectl cannot modify file permissions on control plane nodes, so this finding cannot be fixed through the Kubernetes API. The required changes must be made directly on each control plane node’s filesystem (for /etc/kubernetes/pki/*.crt); follow the guidance in the Manual Steps section to remediate.
Automation
#!/usr/bin/env bash
#
# Purpose: Ensure Kubernetes PKI certificate files have permissions 644 or more restrictive.
# Scope: Run on every control plane node.
# Safely re-runnable: only relaxes overly-permissive perms; leaves stricter perms as-is.
set -euo pipefail
PKI_DIR="/etc/kubernetes/pki"
echo "=== [INFO] Ensuring PKI certificate permissions under ${PKI_DIR} ==="
if [ ! -d "${PKI_DIR}" ]; then
echo "=== [WARN] Directory ${PKI_DIR} does not exist on this node. Nothing to do."
exit 0
fi
# Find all .crt files and fix permissions if they are more permissive than 0644
while IFS= read -r crt; do
# Skip if no file (defensive)
[ -f "${crt}" ] || continue
current_mode_oct=$(stat -c '%a' "${crt}")
# Normalize to 4 digits (e.g., 644 -> 0644) for comparison
current_mode_norm=$(printf "%04d" "${current_mode_oct}")
# Compare current mode to 0644. We only reduce permissions, never relax.
# Breakdown: owner/group/other digits (ignore sticky/setuid/setgid in this simple check).
o=${current_mode_norm:1:1}
g=${current_mode_norm:2:1}
t=${current_mode_norm:3:1}
change_needed=false
# Owner should be <= 6 (r+w). If owner has execute (7) or unexpected bits, reduce to 6.
if [ "${o}" -gt 6 ]; then
change_needed=true
fi
# Group should be <= 4 (r). If group has write/exec, reduce.
if [ "${g}" -gt 4 ]; then
change_needed=true
fi
# Other should be <= 4 (r). If other has write/exec, reduce.
if [ "${t}" -gt 4 ]; then
change_needed=true
fi
if [ "${change_needed}" = true ]; then
echo "Fixing permissions on ${crt} (was ${current_mode_oct}) -> 0644"
chmod 0644 "${crt}"
else
# If mode is already 0644 or more restrictive (e.g., 0600, 0640, 0400, 0444), leave as-is.
echo "Permissions already compliant or more restrictive on ${crt} (mode ${current_mode_oct}), skipping"
fi
done < <(find "${PKI_DIR}" -type f -name '*.crt' 2>/dev/null)
echo "=== [VERIFY] Current permissions for PKI certificates ==="
find "${PKI_DIR}" -name '*.crt' | xargs stat -c 'permissions=%a %n' 2>/dev/null || true
echo "=== [CHECK] Verifying that no .crt file is more permissive than 644 ==="
non_compliant=$(find "${PKI_DIR}" -type f -name '*.crt' -exec stat -c '%a %n' {} \; \
| awk '$1 > 644 {print}')
if [ -n "${non_compliant}" ]; then
echo "=== [FAIL] The following certificate files are still more permissive than 644:"
echo "${non_compliant}"
exit 1
fi
echo "=== [SUCCESS] All Kubernetes PKI certificate files are 644 or more restrictive ==="