cilium/cilium · critical
failed to load or generate private key: %w
Error message
failed to load or generate private key: %w
What it means
The agent's init step loads the WireGuard private key from privKeyPath or generates a new one; any failure (unreadable file, invalid key data, unwritable directory) is wrapped as "failed to load or generate private key". Without a valid private key the node cannot identify itself on the WireGuard mesh.
Source
Thrown at pkg/wireguard/agent/agent.go:286
types.NodeEncryptionOptOutLabels+" label selector",
logfields.Selector, a.config.NodeEncryptionOptOutLabels,
)
localNode.Local.OptOutNodeEncryption = true
localNode.EncryptionKey = 0
}
a.optOut = localNode.Local.OptOutNodeEncryption
}
// init creates and configures the local WireGuard tunnel device.
func (a *Agent) init() error {
a.Lock()
defer a.Unlock()
var err error
a.privKey, err = loadOrGeneratePrivKey(a.privKeyPath)
if err != nil {
return fmt.Errorf("failed to load or generate private key: %w", err)
}
// Best-effort MTU computation: account for WireGuard overhead including padding.
// Without this, the kernel defaults to 1500 - 80 = 1420, ignoring alignment padding.
// Worst case we set 1500 - 95 = 1405; the mtuReconciler will adjust once the MTU table is populated.
deviceMTU := mtu.EthernetMTU
if mtuRoute, _, _, found := a.mtuTable.GetWatch(a.db.ReadTxn(), mtu.MTURouteByPrefix(mtu.DefaultPrefixV4)); found {
deviceMTU = mtuRoute.DeviceMTU
}
linkMTU := deviceMTU - mtu.WireguardOverhead
link := &netlink.Wireguard{
LinkAttrs: netlink.LinkAttrs{
Name: types.IfaceName,
MTU: linkMTU,
},
}
View on GitHub (pinned to ac7b90affa)
Solutions
- Fix permissions on the private key file and its directory so the agent user can read/write.
- Delete the corrupt key file to let the agent generate a fresh one (peers will re-learn the public key).
- Ensure the volume backing privKeyPath is writable and persistent.
- Inspect the wrapped error to distinguish read vs. generate failure.
Example fix
// before chown -R kube-apiserver: /var/lib/cilium/wg # wrong user // after chown -R root:root /var/lib/cilium/wg && chmod 700 /var/lib/cilium/wg
Defensive patterns
Strategy: validation
Validate before calling
// pre-flight: key path must be readable, dir writable
if info, err := os.Stat(privKeyPath); err == nil && info.Mode().Perm()&0400 == 0 {
return errors.New("private key file not readable")
}
if err := os.WriteFile(filepath.Join(filepath.Dir(privKeyPath), ".probe"), nil, 0600); err != nil {
return fmt.Errorf("key dir not writable: %w", err)
} Try / catch
if err := agent.Start(ctx); err != nil {
if strings.Contains(err.Error(), "failed to load or generate private key") {
return fmt.Errorf("fix permissions or delete corrupt key file: %w", err)
}
return err
} Prevention
- Mount the key directory as a writable persistent volume.
- Run the agent as the user owning the key path.
- Probe writability at container startup.
When it happens
Trigger: loadOrGeneratePrivKey fails because the key file exists but is unreadable/corrupt, its parent directory is missing or not writable, or its content is not a valid curve25519 key.
Common situations: Container running as non-root without access to the key path; stale/corrupt key from an interrupted write; read-only root filesystem; key truncated after a node crash.
Related errors
- failed to save wg private key: %w
- failed to load wg private key: %w
- failed to open CA private key file %s: %w
- private key file path is required
- Failed to open file %s for writing: %w
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/ca3955f1b413422e.
Report an issue: GitHub.