Skip to content

Commit 7ac1206

Browse files
committed
feat: verify config server IPs with DNS name
Allow nodeup to connect to IP-based kops-controller config-server endpoints while verifying TLS against kops-controller.internal.<cluster_name>. Signed-off-by: Ciprian Hacman <ciprian@hakman.dev>
1 parent 4fe1979 commit 7ac1206

5 files changed

Lines changed: 84 additions & 22 deletions

File tree

pkg/apis/nodeup/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ type BootConfig struct {
185185
type ConfigServerOptions struct {
186186
// Servers are the addresses of the configuration servers to use (kops-controller)
187187
Servers []string `json:"servers,omitempty"`
188+
// TLSServerName is the server name to use for TLS verification when connecting to Servers.
189+
TLSServerName string `json:"tlsServerName,omitempty"`
188190
// CACertificates are the certificates to trust for fi.CertificateIDCA.
189191
CACertificates string
190192
}

pkg/kopscontrollerclient/client.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ type Client struct {
5252
}
5353

5454
func New(authenticator bootstrap.Authenticator, cas []byte, baseURL url.URL) *Client {
55+
return NewWithTLSServerName(authenticator, cas, baseURL, "")
56+
}
57+
58+
func NewWithTLSServerName(authenticator bootstrap.Authenticator, cas []byte, baseURL url.URL, tlsServerName string) *Client {
5559
client := &Client{
5660
Authenticator: authenticator,
5761
CAs: cas,
@@ -60,11 +64,15 @@ func New(authenticator bootstrap.Authenticator, cas []byte, baseURL url.URL) *Cl
6064

6165
certPool := x509.NewCertPool()
6266
certPool.AppendCertsFromPEM(cas)
67+
tlsConfig := &tls.Config{
68+
RootCAs: certPool,
69+
MinVersion: tls.VersionTLS12,
70+
}
71+
if tlsServerName != "" {
72+
tlsConfig.ServerName = tlsServerName
73+
}
6374
transport := &http.Transport{
64-
TLSClientConfig: &tls.Config{
65-
RootCAs: certPool,
66-
MinVersion: tls.VersionTLS12,
67-
},
75+
TLSClientConfig: tlsConfig,
6876
}
6977
client.httpClient = &http.Client{
7078
Timeout: time.Duration(15) * time.Second,

pkg/nodemodel/nodeupconfigbuilder.go

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -393,23 +393,7 @@ func (n *nodeUpConfigBuilder) BuildConfig(ig *kops.InstanceGroup, wellKnownAddre
393393

394394
useConfigServer := kopsmodel.UseKopsControllerForNodeConfig(cluster) && !ig.HasAPIServer()
395395
if useConfigServer {
396-
hosts := []string{"kops-controller.internal." + cluster.ObjectMeta.Name}
397-
if len(bootConfig.APIServerIPs) > 0 {
398-
hosts = bootConfig.APIServerIPs
399-
}
400-
401-
configServer := &nodeup.ConfigServerOptions{
402-
CACertificates: config.CAs[fi.CertificateIDCA],
403-
}
404-
for _, host := range hosts {
405-
baseURL := url.URL{
406-
Scheme: "https",
407-
Host: net.JoinHostPort(host, strconv.Itoa(wellknownports.KopsControllerPort)),
408-
Path: "/",
409-
}
410-
configServer.Servers = append(configServer.Servers, baseURL.String())
411-
}
412-
bootConfig.ConfigServer = configServer
396+
bootConfig.ConfigServer = buildConfigServerOptions(cluster.ObjectMeta.Name, config.CAs[fi.CertificateIDCA], bootConfig.APIServerIPs)
413397
delete(config.CAs, fi.CertificateIDCA)
414398
} else {
415399
bootConfig.ConfigBase = fi.PtrTo(n.configBase.Path())
@@ -465,6 +449,30 @@ func (n *nodeUpConfigBuilder) BuildConfig(ig *kops.InstanceGroup, wellKnownAddre
465449
return config, bootConfig, nil
466450
}
467451

452+
func buildConfigServerOptions(clusterName string, caCertificates string, apiserverIPs []string) *nodeup.ConfigServerOptions {
453+
kopsControllerName := "kops-controller.internal." + clusterName
454+
hosts := []string{kopsControllerName}
455+
456+
configServer := &nodeup.ConfigServerOptions{
457+
CACertificates: caCertificates,
458+
}
459+
if len(apiserverIPs) > 0 {
460+
hosts = apiserverIPs
461+
configServer.TLSServerName = kopsControllerName
462+
}
463+
464+
for _, host := range hosts {
465+
baseURL := url.URL{
466+
Scheme: "https",
467+
Host: net.JoinHostPort(host, strconv.Itoa(wellknownports.KopsControllerPort)),
468+
Path: "/",
469+
}
470+
configServer.Servers = append(configServer.Servers, baseURL.String())
471+
}
472+
473+
return configServer
474+
}
475+
468476
func loadCertificates(keysets map[string]*fi.Keyset, name string, config *nodeup.Config, includeKeypairID bool) error {
469477
keyset := keysets[name]
470478
if keyset == nil {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
Copyright 2026 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package nodemodel
18+
19+
import (
20+
"reflect"
21+
"testing"
22+
)
23+
24+
func TestBuildConfigServerOptionsUsesTLSServerNameForIPServers(t *testing.T) {
25+
options := buildConfigServerOptions("cluster.k8s.local", "ca-data", []string{"10.0.1.2"})
26+
27+
if got, want := options.TLSServerName, "kops-controller.internal.cluster.k8s.local"; got != want {
28+
t.Fatalf("TLSServerName = %q, want %q", got, want)
29+
}
30+
if got, want := options.Servers, []string{"https://10.0.1.2:3988/"}; !reflect.DeepEqual(got, want) {
31+
t.Fatalf("Servers = %v, want %v", got, want)
32+
}
33+
}
34+
35+
func TestBuildConfigServerOptionsUsesDNSNameByDefault(t *testing.T) {
36+
options := buildConfigServerOptions("cluster.k8s.local", "ca-data", nil)
37+
38+
if options.TLSServerName != "" {
39+
t.Fatalf("TLSServerName = %q, want empty", options.TLSServerName)
40+
}
41+
if got, want := options.Servers, []string{"https://kops-controller.internal.cluster.k8s.local:3988/"}; !reflect.DeepEqual(got, want) {
42+
t.Fatalf("Servers = %v, want %v", got, want)
43+
}
44+
}

upup/pkg/fi/nodeup/command.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ func getNodeConfigFromServers(ctx context.Context, bootConfig *nodeup.BootConfig
738738
}
739739

740740
// Note: The url is overridden in every iteration of the loop below.
741-
client := kopscontrollerclient.New(authenticator, []byte(bootConfig.ConfigServer.CACertificates), url.URL{})
741+
client := kopscontrollerclient.NewWithTLSServerName(authenticator, []byte(bootConfig.ConfigServer.CACertificates), url.URL{}, bootConfig.ConfigServer.TLSServerName)
742742
defer client.Close()
743743

744744
var merr error

0 commit comments

Comments
 (0)