fix(pki): stop regenerating CA on restart; add --node-ip for multi-NIC hosts [KS-69]#167
Merged
Conversation
…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
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
There was a problem hiding this comment.
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_IPto 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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: