Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/talosctl/cmd/talos/apply-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ var applyConfigCmd = &cobra.Command{
return WithClientMaintenance(applyConfigCmdFlags.certFingerprints, f)
}

if GlobalArgs.SkipVerify {
return WithClientSkipVerify(f)
}

return WithClient(f)
}

Expand Down
4 changes: 4 additions & 0 deletions cmd/talosctl/cmd/talos/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ To get a list of all available resource definitions, issue 'talosctl get rd'`,
return WithClientMaintenance(nil, getResources(args))
}

if GlobalArgs.SkipVerify {
return WithClientSkipVerify(getResources(args))
}

return WithClient(getResources(args))
},
}
Expand Down
8 changes: 8 additions & 0 deletions cmd/talosctl/cmd/talos/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ var metaWriteCmd = &cobra.Command{
return WithClientMaintenance(nil, fn)
}

if GlobalArgs.SkipVerify {
return WithClientSkipVerify(fn)
}

return WithClient(fn)
},
}
Expand All @@ -66,6 +70,10 @@ var metaDeleteCmd = &cobra.Command{
return WithClientMaintenance(nil, fn)
}

if GlobalArgs.SkipVerify {
return WithClientSkipVerify(fn)
}

return WithClient(fn)
},
}
Expand Down
4 changes: 4 additions & 0 deletions cmd/talosctl/cmd/talos/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ var resetCmd = &cobra.Command{
return WithClientMaintenance(nil, resetNoWait)
}

if GlobalArgs.SkipVerify {
return WithClientSkipVerify(resetNoWait)
}

return WithClient(resetNoWait)
}

Expand Down
7 changes: 7 additions & 0 deletions cmd/talosctl/cmd/talos/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ func WithClientMaintenance(enforceFingerprints []string, action func(context.Con
return GlobalArgs.WithClientMaintenance(enforceFingerprints, action)
}

// WithClientSkipVerify wraps common code to initialize Talos client with TLS verification disabled
// but with client certificate authentication preserved.
func WithClientSkipVerify(action func(context.Context, *client.Client) error) error {
return GlobalArgs.WithClientSkipVerify(action)
}

// Commands is a list of commands published by the package.
var Commands []*cobra.Command

Expand Down Expand Up @@ -81,6 +87,7 @@ func addCommand(cmd *cobra.Command) {
),
)
cli.Should(cmd.RegisterFlagCompletionFunc("context", CompleteConfigContext))
cmd.PersistentFlags().BoolVar(&GlobalArgs.SkipVerify, "skip-verify", false, "skip TLS certificate verification (keeps client authentication)")

Commands = append(Commands, cmd)
}
Expand Down
4 changes: 4 additions & 0 deletions cmd/talosctl/cmd/talos/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ func runUpgradeNoWait(opts []client.UpgradeOption) error {
return WithClientMaintenance(nil, upgradeFn)
}

if GlobalArgs.SkipVerify {
return WithClientSkipVerify(upgradeFn)
}

return WithClient(upgradeFn)
}

Expand Down
4 changes: 4 additions & 0 deletions cmd/talosctl/cmd/talos/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ var versionCmd = &cobra.Command{
return WithClientMaintenance(nil, cmdVersion)
}

if GlobalArgs.SkipVerify {
return WithClientSkipVerify(cmdVersion)
}

return WithClient(cmdVersion)
},
}
Expand Down
4 changes: 4 additions & 0 deletions cmd/talosctl/cmd/talos/wipe.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ Use device names as arguments, for example: vda or sda5.`,
return WithClientMaintenance(nil, cmdWipe(args))
}

if GlobalArgs.SkipVerify {
return WithClientSkipVerify(cmdWipe(args))
}

return WithClient(cmdWipe(args))
},
}
Expand Down
85 changes: 85 additions & 0 deletions cmd/talosctl/pkg/talos/global/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package global
import (
"context"
"crypto/tls"
"encoding/base64"
"errors"
"fmt"

Expand All @@ -27,6 +28,7 @@ type Args struct {
Nodes []string
Endpoints []string
SideroV1KeysDir string
SkipVerify bool
}

// NodeList returns the list of nodes to run the command against.
Expand All @@ -38,6 +40,11 @@ func (c *Args) NodeList() []string {
//
// WithClientNoNodes doesn't set any node information on the request context.
func (c *Args) WithClientNoNodes(action func(context.Context, *client.Client) error, dialOptions ...grpc.DialOption) error {
// If SkipVerify is set, use WithClientSkipVerify instead
if c.SkipVerify {
return c.WithClientSkipVerify(action)
}

return cli.WithContext(
context.Background(), func(ctx context.Context) error {
cfg, err := clientconfig.Open(c.Talosconfig)
Expand Down Expand Up @@ -140,3 +147,81 @@ func (c *Args) WithClientMaintenance(enforceFingerprints []string, action func(c
},
)
}

// WithClientSkipVerify wraps common code to initialize Talos client with TLS verification disabled
// but with client certificate authentication preserved.
// This is useful when connecting to nodes via IP addresses not listed in the server certificate's SANs.
func (c *Args) WithClientSkipVerify(action func(context.Context, *client.Client) error) error {
return cli.WithContext(
context.Background(), func(ctx context.Context) error {
cfg, err := clientconfig.Open(c.Talosconfig)
if err != nil {
return fmt.Errorf("failed to open config file %q: %w", c.Talosconfig, err)
}

// Get context name - use override if specified, otherwise use default
contextName := c.CmdContext
if contextName == "" {
contextName = cfg.Context
}

configContext, ok := cfg.Contexts[contextName]
if !ok {
return fmt.Errorf("context %q not found in config", contextName)
}

// Build TLS config with InsecureSkipVerify but preserve client certificate
tlsConfig := &tls.Config{
InsecureSkipVerify: true,
}

// Add client certificate if available
if configContext.Crt != "" && configContext.Key != "" {
crtBytes, err := base64.StdEncoding.DecodeString(configContext.Crt)
if err != nil {
return fmt.Errorf("error decoding certificate: %w", err)
}

keyBytes, err := base64.StdEncoding.DecodeString(configContext.Key)
if err != nil {
return fmt.Errorf("error decoding key: %w", err)
}

cert, err := tls.X509KeyPair(crtBytes, keyBytes)
if err != nil {
return fmt.Errorf("could not load client key pair: %w", err)
}

tlsConfig.Certificates = []tls.Certificate{cert}
}

opts := []client.OptionFunc{
client.WithTLSConfig(tlsConfig),
client.WithDefaultGRPCDialOptions(),
}

// Use endpoints from command-line flags or config
if len(c.Endpoints) > 0 {
opts = append(opts, client.WithEndpoints(c.Endpoints...))
} else if len(configContext.Endpoints) > 0 {
opts = append(opts, client.WithEndpoints(configContext.Endpoints...))
}

cli, err := client.New(ctx, opts...)
if err != nil {
return fmt.Errorf("error constructing client: %w", err)
}
//nolint:errcheck
defer cli.Close()

// Set nodes on context
if len(c.Nodes) > 0 {
ctx = client.WithNodes(ctx, c.Nodes...)
} else if len(configContext.Nodes) > 0 {
ctx = client.WithNodes(ctx, configContext.Nodes...)
}

return action(ctx, cli)
},
)
}