Skip to content

fix(pki): stop regenerating CA on restart; add --node-ip for multi-NIC hosts [KS-69]#167

Merged
stevensbkang merged 4 commits into
developfrom
fix/ks-69/node-ip
Jul 8, 2026
Merged

fix(pki): stop regenerating CA on restart; add --node-ip for multi-NIC hosts [KS-69]#167
stevensbkang merged 4 commits into
developfrom
fix/ks-69/node-ip

Conversation

@stevensbkang

Copy link
Copy Markdown
Member

On hosts with multiple NICs, GetNodeIP() returned the first non-loopback IPv4 from InterfaceAddrs() with no ordering guarantee, so the detected node IP could flip between reboots. That made the apiserver cert SANs "not cover" the current IP, triggering InvalidateIfIPChanged to os.RemoveAll the entire PKI tree — including the CA. The rebuilt CA no longer matched the one embedded in users kubeconfigs, forcing a re-copy after every restart.

Changes:

  • Add --node-ip flag (env KUBESOLO_NODE_IP) to pin the node IP used for the apiserver advertise-address, kubeconfig, kubelet node-IP and LoadBalancer EXTERNAL-IP. Valid-but-non-local values (VIPs) are allowed with a warning; unparseable values fall back to auto-detection.
  • Prefer a private (RFC 1918) address during auto-detection and make selection deterministic regardless of InterfaceAddrs ordering.
  • Preserve the CA and request-header CA in InvalidateIfIPChanged; remove only leaf certs so GenerateAllCertificates re-signs with the existing CA. Client auth validates against the CA, so previously distributed kubeconfigs keep working across restarts.
  • Mirror --node-ip in the kubesolo install CLI

…C hosts

On hosts with multiple NICs, GetNodeIP() returned the first non-loopback IPv4
from InterfaceAddrs() with no ordering guarantee, so the detected node IP could
flip between reboots. That made the apiserver cert SANs "not cover" the current
IP, triggering InvalidateIfIPChanged to os.RemoveAll the entire PKI tree —
including the CA. The rebuilt CA no longer matched the one embedded in users
kubeconfigs, forcing a re-copy after every restart.

Changes:
- Add --node-ip flag (env KUBESOLO_NODE_IP) to pin the node IP used for the
  apiserver advertise-address, kubeconfig, kubelet node-IP and LoadBalancer
  EXTERNAL-IP. Valid-but-non-local values (VIPs) are allowed with a warning;
  unparseable values fall back to auto-detection.
- Prefer a private (RFC 1918) address during auto-detection and make selection
  deterministic regardless of InterfaceAddrs ordering.
- Preserve the CA and request-header CA in InvalidateIfIPChanged; remove only
  leaf certs so GenerateAllCertificates re-signs with the existing CA. Client
  auth validates against the CA, so previously distributed kubeconfigs keep
  working across restarts.
- Mirror --node-ip in the kubesolo install CLI
@linear

linear Bot commented Jul 8, 2026

Copy link
Copy Markdown

KS-69

When --node-ip is provided, the API server serving certificate now covers only
that IP plus the in-cluster service IP and localhost (and --apiserver-extra-sans),
instead of every local interface address. This stops the cert from vouching for
unrelated NICs such as a public interface. Auto-detection (no --node-ip) keeps
the original all-local-IPs behavior. The PKI IP-change check now validates the
advertised node IP against the cert SANs so scoped certs are not regenerated on
every boot

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens KubeSolo’s node IP handling on multi-NIC hosts and adjusts PKI regeneration behavior so node IP changes don’t rotate the cluster CA (preserving existing kubeconfigs).

Changes:

  • Adds --node-ip / KUBESOLO_NODE_IP to pin the advertised node IP (and propagates it through the installer CLI).
  • Improves node IP auto-detection to prefer private IPv4 and introduces ResolveNodeIP() validation/warnings.
  • Updates PKI invalidation to preserve CA directories and only regenerate leaf certificates; scopes apiserver cert SANs differently when the node IP is pinned.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
types/types.go Adds NodeIPSpecified to carry whether node IP was explicitly set.
pkg/kubernetes/kubelet/args.go Ensures kubelet registers with the resolved node IP via --node-ip when valid.
internal/runtime/network/ip.go Adds ResolveNodeIP() and updates node IP selection logic.
internal/runtime/network/ip_test.go Adds tests for node IP selection and override behavior.
internal/core/pki/validate.go Preserves CA/request-header CA and regenerates only leaf certs on invalidation.
internal/core/pki/validate_test.go Updates tests to assert CA preservation and leaf regeneration behavior.
internal/core/pki/options.go Scopes apiserver serving cert SANs when node IP is pinned.
internal/core/pki/options_test.go Adds coverage for pinned SAN scoping behavior.
internal/config/flags/flags.go Introduces --node-ip flag (kingpin) with env var support.
internal/cli/config/config.go Mirrors node-ip into installer config and generated cmd args.
internal/cli/cmd_install.go Adds --node-ip flag to the installer’s Cobra CLI.
cmd/kubesolo/main.go Wires ResolveNodeIP() into bootstrap and records NodeIPSpecified.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/kubesolo/main.go Outdated
Comment thread internal/runtime/network/ip.go
Comment thread internal/runtime/network/ip_test.go Outdated
Comment thread internal/core/pki/validate.go
Comment thread internal/core/pki/validate.go
@stevensbkang
stevensbkang merged commit e131cbf into develop Jul 8, 2026
15 checks passed
@stevensbkang
stevensbkang deleted the fix/ks-69/node-ip branch July 8, 2026 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants