From f37da96ef3e3116f0040c567be408b23fed957de Mon Sep 17 00:00:00 2001 From: Philipp Sauter Date: Thu, 11 Aug 2022 15:25:57 +0200 Subject: [PATCH] feat: enable talos client to connect to Talos through an auth proxy Talos client can connect to Talos API via a proxy with basic auth. Additionally it is now optional to specify a TLS CA,key or crt. Optionally Developers can build talosctl with WITH_DEBUG=1 to allow insecure connections when http:// endpoints are specified. Fixes #5980 Signed-off-by: Philipp Sauter --- cmd/talosctl/cmd/root.go | 1 + cmd/talosctl/cmd/talos/root.go | 11 +- pkg/machinery/client/basic_auth.go | 33 ++++ pkg/machinery/client/client.go | 121 ++---------- pkg/machinery/client/config/config.go | 19 +- pkg/machinery/client/connection.go | 187 ++++++++++++++++++ pkg/machinery/client/connection_test.go | 151 ++++++++++++++ pkg/machinery/client/export_test.go | 19 ++ .../client/grpc_connection_wrapper.go | 46 +++++ pkg/machinery/client/insecure_credentials.go | 47 +++++ pkg/machinery/client/options.go | 12 +- pkg/machinery/client/secure_credentials.go | 28 +++ .../types/v1alpha1/generate/generate_test.go | 8 +- website/content/v1.2/reference/cli.md | 70 +++++++ 14 files changed, 641 insertions(+), 112 deletions(-) create mode 100644 pkg/machinery/client/basic_auth.go create mode 100644 pkg/machinery/client/connection.go create mode 100644 pkg/machinery/client/connection_test.go create mode 100644 pkg/machinery/client/export_test.go create mode 100644 pkg/machinery/client/grpc_connection_wrapper.go create mode 100644 pkg/machinery/client/insecure_credentials.go create mode 100644 pkg/machinery/client/secure_credentials.go diff --git a/cmd/talosctl/cmd/root.go b/cmd/talosctl/cmd/root.go index e49969422..7432d2bef 100644 --- a/cmd/talosctl/cmd/root.go +++ b/cmd/talosctl/cmd/root.go @@ -46,6 +46,7 @@ func Execute() error { rootCmd.PersistentFlags().StringSliceVarP(&talos.Endpoints, "endpoints", "e", []string{}, "override default endpoints in Talos configuration") cli.Should(rootCmd.RegisterFlagCompletionFunc("context", talos.CompleteConfigContext)) cli.Should(rootCmd.RegisterFlagCompletionFunc("nodes", talos.CompleteNodes)) + rootCmd.PersistentFlags().StringVar(&talos.Cluster, "cluster", "", "Cluster to connect to if a proxy endpoint is used.") cmd, err := rootCmd.ExecuteC() if err != nil { diff --git a/cmd/talosctl/cmd/talos/root.go b/cmd/talosctl/cmd/talos/root.go index 4b199e610..16e2b6c06 100644 --- a/cmd/talosctl/cmd/talos/root.go +++ b/cmd/talosctl/cmd/talos/root.go @@ -37,13 +37,14 @@ var ( Endpoints []string Nodes []string Cmdcontext string + Cluster string ) const pathAutoCompleteLimit = 500 // WithClientNoNodes wraps common code to initialize Talos client and provide cancellable context. // -// WithClientNoNodes doesn't set any node information on request context. +// WithClientNoNodes doesn't set any node information on the request context. func WithClientNoNodes(action func(context.Context, *client.Client) error) error { return cli.WithContext( context.Background(), func(ctx context.Context) error { @@ -65,6 +66,10 @@ func WithClientNoNodes(action func(context.Context, *client.Client) error) error opts = append(opts, client.WithEndpoints(Endpoints...)) } + if Cluster != "" { + opts = append(opts, client.WithCluster(Cluster)) + } + c, err := client.New(ctx, opts...) if err != nil { return fmt.Errorf("error constructing client: %w", err) @@ -77,6 +82,8 @@ func WithClientNoNodes(action func(context.Context, *client.Client) error) error ) } +var errConfigContext = fmt.Errorf("failed to resolve config context") + // WithClient builds upon WithClientNoNodes to provide set of nodes on request context based on config & flags. func WithClient(action func(context.Context, *client.Client) error) error { return WithClientNoNodes( @@ -84,7 +91,7 @@ func WithClient(action func(context.Context, *client.Client) error) error { if len(Nodes) < 1 { configContext := c.GetConfigContext() if configContext == nil { - return fmt.Errorf("failed to resolve config context") + return errConfigContext } Nodes = configContext.Nodes diff --git a/pkg/machinery/client/basic_auth.go b/pkg/machinery/client/basic_auth.go new file mode 100644 index 000000000..b2f79b91a --- /dev/null +++ b/pkg/machinery/client/basic_auth.go @@ -0,0 +1,33 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package client + +import ( + "context" + "encoding/base64" + + "google.golang.org/grpc" +) + +// BasicAuth implements the credentials.PerRPCCredentials interface and holds credentials for Basic Auth. +type BasicAuth struct { + auth string +} + +// GetRequestMetadata implements credentials.PerGRPCCredentials. +func (c BasicAuth) GetRequestMetadata(ctx context.Context, url ...string) (map[string]string, error) { + enc := base64.StdEncoding.EncodeToString([]byte(c.auth)) + + return map[string]string{ + "Authorization": "Basic " + enc, + }, nil +} + +// WithGRPCBasicAuth returns gRPC credentials for basic auth. +func WithGRPCBasicAuth(username, password string) grpc.DialOption { + return grpc.WithPerRPCCredentials(BasicAuth{ + auth: username + ":" + password, + }) +} diff --git a/pkg/machinery/client/client.go b/pkg/machinery/client/client.go index 115d2444c..d559ac5a0 100644 --- a/pkg/machinery/client/client.go +++ b/pkg/machinery/client/client.go @@ -10,21 +10,16 @@ import ( "bytes" "compress/gzip" "context" - "crypto/tls" - "encoding/base64" "errors" "fmt" "io" - "strings" "time" cosiv1alpha1 "github.com/cosi-project/runtime/api/v1alpha1" "github.com/cosi-project/runtime/pkg/state" "github.com/cosi-project/runtime/pkg/state/protobuf/client" - grpctls "github.com/talos-systems/crypto/tls" "google.golang.org/grpc" "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/emptypb" @@ -37,22 +32,13 @@ import ( storageapi "github.com/talos-systems/talos/pkg/machinery/api/storage" timeapi "github.com/talos-systems/talos/pkg/machinery/api/time" clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config" - "github.com/talos-systems/talos/pkg/machinery/client/resolver" - "github.com/talos-systems/talos/pkg/machinery/constants" ) -// Credentials represents the set of values required to initialize a valid -// Client. -type Credentials struct { - CA []byte - Crt tls.Certificate -} - // Client implements the proto.MachineServiceClient interface. It serves as the // concrete type with the required methods. type Client struct { options *Options - conn *grpc.ClientConn + conn *grpcConnectionWrapper MachineClient machineapi.MachineServiceClient TimeClient timeapi.TimeServiceClient @@ -138,6 +124,24 @@ func (c *Client) GetEndpoints() []string { return nil } +// GetClusterName returns the client's cluster name from the override set with WithClustername +// or from the configuration. +func (c *Client) GetClusterName() string { + if c.options.clusterNameOverride != "" { + return c.options.clusterNameOverride + } + + if c.options.config != nil { + if err := c.resolveConfigContext(); err != nil { + return "" + } + + return c.options.configContext.Cluster + } + + return "" +} + // New returns a new Client. func New(ctx context.Context, opts ...OptionFunc) (c *Client, err error) { c = new(Client) @@ -173,93 +177,6 @@ func New(ctx context.Context, opts ...OptionFunc) (c *Client, err error) { return c, nil } -// getConn creates new gRPC connection. -func (c *Client) getConn(ctx context.Context, opts ...grpc.DialOption) (*grpc.ClientConn, error) { - endpoints := resolver.EnsureEndpointsHavePorts(c.GetEndpoints(), constants.ApidPort) - - var target string - - switch { - case c.options.unixSocketPath != "": - target = fmt.Sprintf("unix:///%s", c.options.unixSocketPath) - case len(endpoints) > 1: - target = fmt.Sprintf("%s:///%s", resolver.RoundRobinResolverScheme, strings.Join(endpoints, ",")) - default: - // NB: we use the `dns` scheme here in order to handle fancier situations - // when there is a single endpoint. - // Such possibilities include SRV records, multiple IPs from A and/or AAAA - // records, and descriptive TXT records which include things like load - // balancer specs. - target = fmt.Sprintf("dns:///%s", endpoints[0]) - } - - dialOpts := []grpc.DialOption(nil) - - if c.options.unixSocketPath == "" { - // Add TLS credentials to gRPC DialOptions - tlsConfig := c.options.tlsConfig - if tlsConfig == nil { - if err := c.resolveConfigContext(); err != nil { - return nil, fmt.Errorf("failed to resolve configuration context: %w", err) - } - - creds, err := CredentialsFromConfigContext(c.options.configContext) - if err != nil { - return nil, fmt.Errorf("failed to acquire credentials: %w", err) - } - - tlsConfig, err = grpctls.New( - grpctls.WithKeypair(creds.Crt), - grpctls.WithClientAuthType(grpctls.Mutual), - grpctls.WithCACertPEM(creds.CA), - ) - if err != nil { - return nil, fmt.Errorf("failed to construct TLS credentials: %w", err) - } - } - - dialOpts = append(dialOpts, - grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)), - grpc.WithInitialWindowSize(65535*32), - grpc.WithInitialConnWindowSize(65535*16), - ) - } - - dialOpts = append(dialOpts, c.options.grpcDialOptions...) - - dialOpts = append(dialOpts, opts...) - - return grpc.DialContext(ctx, target, dialOpts...) -} - -// CredentialsFromConfigContext constructs the client Credentials from the given configuration Context. -func CredentialsFromConfigContext(context *clientconfig.Context) (*Credentials, error) { - caBytes, err := base64.StdEncoding.DecodeString(context.CA) - if err != nil { - return nil, fmt.Errorf("error decoding CA: %w", err) - } - - crtBytes, err := base64.StdEncoding.DecodeString(context.Crt) - if err != nil { - return nil, fmt.Errorf("error decoding certificate: %w", err) - } - - keyBytes, err := base64.StdEncoding.DecodeString(context.Key) - if err != nil { - return nil, fmt.Errorf("error decoding key: %w", err) - } - - crt, err := tls.X509KeyPair(crtBytes, keyBytes) - if err != nil { - return nil, fmt.Errorf("could not load client key pair: %s", err) - } - - return &Credentials{ - CA: caBytes, - Crt: crt, - }, nil -} - // Close shuts down client protocol. func (c *Client) Close() error { return c.conn.Close() diff --git a/pkg/machinery/client/config/config.go b/pkg/machinery/client/config/config.go index 6e5348449..92642f9fc 100644 --- a/pkg/machinery/client/config/config.go +++ b/pkg/machinery/client/config/config.go @@ -51,9 +51,22 @@ type Context struct { DeprecatedTarget string `yaml:"target,omitempty"` // Field deprecated in favor of Endpoints Endpoints []string `yaml:"endpoints"` Nodes []string `yaml:"nodes,omitempty"` - CA string `yaml:"ca"` - Crt string `yaml:"crt"` - Key string `yaml:"key"` + CA string `yaml:"ca,omitempty"` + Crt string `yaml:"crt,omitempty"` + Key string `yaml:"key,omitempty"` + Auth Auth `yaml:"auth,omitempty"` + Cluster string `yaml:"cluster,omitempty"` +} + +// Auth may hold credentials for an authentication method such as Basic Auth. +type Auth struct { + Basic *Basic `yaml:"basic,omitempty"` +} + +// Basic holds Basic Auth credentials. +type Basic struct { + Username string `yaml:"username"` + Password string `yaml:"password"` } func (c *Context) upgrade() { diff --git a/pkg/machinery/client/connection.go b/pkg/machinery/client/connection.go new file mode 100644 index 000000000..00a809881 --- /dev/null +++ b/pkg/machinery/client/connection.go @@ -0,0 +1,187 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package client + +import ( + "context" + "crypto/tls" + "crypto/x509" + "encoding/base64" + "fmt" + "net" + "net/url" + "strings" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + + clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config" + "github.com/talos-systems/talos/pkg/machinery/client/resolver" + "github.com/talos-systems/talos/pkg/machinery/constants" + "github.com/talos-systems/talos/pkg/machinery/generic/slices" +) + +// getConn creates new gRPC connection. +func (c *Client) getConn(ctx context.Context, opts ...grpc.DialOption) (*grpcConnectionWrapper, error) { + endpoints := c.GetEndpoints() + + target := c.getTarget( + resolver.EnsureEndpointsHavePorts( + reduceURLsToAddresses(endpoints), + constants.ApidPort), + ) + + dialOpts := []grpc.DialOption(nil) + + dialOpts = append(dialOpts, c.options.grpcDialOptions...) + + dialOpts = append(dialOpts, opts...) + + if c.options.unixSocketPath != "" { + conn, err := grpc.DialContext(ctx, target, dialOpts...) + + return newGRPCConnectionWrapper(c.GetClusterName(), conn), err + } + + tlsConfig := c.options.tlsConfig + + if tlsConfig != nil { + return c.makeConnection(ctx, target, credentials.NewTLS(tlsConfig), dialOpts) + } + + if err := c.resolveConfigContext(); err != nil { + return nil, fmt.Errorf("failed to resolve configuration context: %w", err) + } + + basicAuth := c.options.configContext.Auth.Basic + if basicAuth != nil { + dialOpts = append(dialOpts, WithGRPCBasicAuth(basicAuth.Username, basicAuth.Password)) + } + + creds, err := buildCredentials(c.options.configContext, endpoints) + if err != nil { + return nil, err + } + + return c.makeConnection(ctx, target, creds, dialOpts) +} + +func buildTLSConfig(configContext *clientconfig.Context) (*tls.Config, error) { + tlsConfig := &tls.Config{} + + caBytes, err := getCA(configContext) + if err != nil { + return nil, fmt.Errorf("failed to get CA: %w", err) + } + + if len(caBytes) > 0 { + tlsConfig.RootCAs = x509.NewCertPool() + + if ok := tlsConfig.RootCAs.AppendCertsFromPEM(caBytes); !ok { + return nil, fmt.Errorf("failed to append CA certificate to RootCAs pool") + } + } + + crt, err := CertificateFromConfigContext(configContext) + if err != nil { + return nil, fmt.Errorf("failed to acquire credentials: %w", err) + } + + if crt != nil { + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert + tlsConfig.Certificates = append(tlsConfig.Certificates, *crt) + } + + return tlsConfig, nil +} + +func (c *Client) makeConnection(ctx context.Context, target string, creds credentials.TransportCredentials, dialOpts []grpc.DialOption) (*grpcConnectionWrapper, error) { + dialOpts = append(dialOpts, + grpc.WithTransportCredentials(creds), + grpc.WithInitialWindowSize(65535*32), + grpc.WithInitialConnWindowSize(65535*16)) + + conn, err := grpc.DialContext(ctx, target, dialOpts...) + + return newGRPCConnectionWrapper(c.GetClusterName(), conn), err +} + +func (c *Client) getTarget(endpoints []string) string { + switch { + case c.options.unixSocketPath != "": + return fmt.Sprintf("unix:///%s", c.options.unixSocketPath) + case len(endpoints) > 1: + return fmt.Sprintf("%s:///%s", resolver.RoundRobinResolverScheme, strings.Join(endpoints, ",")) + default: + // NB: we use the `dns` scheme here in order to handle fancier situations + // when there is a single endpoint. + // Such possibilities include SRV records, multiple IPs from A and/or AAAA + // records, and descriptive TXT records which include things like load + // balancer specs. + return fmt.Sprintf("dns:///%s", endpoints[0]) + } +} + +func getCA(context *clientconfig.Context) ([]byte, error) { + if context.CA == "" { + return nil, nil + } + + caBytes, err := base64.StdEncoding.DecodeString(context.CA) + if err != nil { + return nil, fmt.Errorf("error decoding CA: %w", err) + } + + return caBytes, err +} + +// CertificateFromConfigContext constructs the client Credentials from the given configuration Context. +func CertificateFromConfigContext(context *clientconfig.Context) (*tls.Certificate, error) { + if context.Crt == "" && context.Key == "" { + return nil, nil + } + + crtBytes, err := base64.StdEncoding.DecodeString(context.Crt) + if err != nil { + return nil, fmt.Errorf("error decoding certificate: %w", err) + } + + keyBytes, err := base64.StdEncoding.DecodeString(context.Key) + if err != nil { + return nil, fmt.Errorf("error decoding key: %w", err) + } + + crt, err := tls.X509KeyPair(crtBytes, keyBytes) + if err != nil { + return nil, fmt.Errorf("could not load client key pair: %s", err) + } + + return &crt, nil +} + +func reduceURLsToAddresses(endpoints []string) []string { + return slices.Map(endpoints, func(endpoint string) string { + u, err := url.Parse(endpoint) + if err != nil { + return endpoint + } + + if u.Scheme == "https" && u.Port() == "" { + return net.JoinHostPort(u.Hostname(), "443") + } + + if u.Scheme != "" { + if u.Port() != "" { + return net.JoinHostPort(u.Hostname(), u.Port()) + } + + if u.Opaque == "" { + return u.Host + } + } + + return endpoint + }) +} diff --git a/pkg/machinery/client/connection_test.go b/pkg/machinery/client/connection_test.go new file mode 100644 index 000000000..4dffe17b4 --- /dev/null +++ b/pkg/machinery/client/connection_test.go @@ -0,0 +1,151 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package client_test + +import ( + "crypto/tls" + "crypto/x509" + "encoding/base64" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/talos-systems/talos/pkg/machinery/client" + clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config" +) + +func TestReduceURLsToAddresses(t *testing.T) { + endpoints := []string{ + "123.123.123.123", + "exammple.com:111", + "234.234.234.234:4000", + "https://111.111.222.222:444", + "localhost", + "localhost:890", + "https://[42a1:cfa:5458:3967:e2ce:afaa:6194:12f]:40000", + "https://localhost:890", + "2001:db8:0:0:0:ff00:42:8329", + "https://[be4d:c25e:aca0:9366:68b7:c84:a23b:f7be]", + "https://www.somecompany.com", + "www.company.com", + "[2001:db8:4006:812::200e]:8080", + "grpc://222.22.2.1", + "grpc://[794b:389:73cb:76a2:59de:62fd:ee38:7c]:111", + } + expected := []string{ + "123.123.123.123", + "exammple.com:111", + "234.234.234.234:4000", + "111.111.222.222:444", + "localhost", + "localhost:890", + "[42a1:cfa:5458:3967:e2ce:afaa:6194:12f]:40000", + "localhost:890", + "2001:db8:0:0:0:ff00:42:8329", + "[be4d:c25e:aca0:9366:68b7:c84:a23b:f7be]:443", + "www.somecompany.com:443", + "www.company.com", + "[2001:db8:4006:812::200e]:8080", + "222.22.2.1", + "[794b:389:73cb:76a2:59de:62fd:ee38:7c]:111", + } + + actual := client.ReduceURLsToAddresses(endpoints) + + assert.Equal(t, expected, actual) +} + +func TestBuildTLSConfig(t *testing.T) { + //nolint:lll + ca := `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEFtbGVURnRuRVY3b3NHYTJFSU9RVUJNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU1qQTRNVEl4T0RNeE1EZGFGdzB6TWpBNE1Ea3hPRE14TURkYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBVGZ3RjFMQjVwVjg2cGw4cHN2aS93R2dWWmkvTm5NME8wYUZNCjBoenZZdzZqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVWTRhSGg3UnJxRnVObFNydAo4bXY4ZHduUjRKQXdCUVlESzJWd0EwRUFTaE5jYURXMGwrU24xYSt5c21Sd2M2NGlBa3Y5dUlZNGdXU0t3RWJ4CnpYQlR3SkZWcmNPWlZNNS9pM0Y0UjFWZVkzM3QwdFBQMFBGZVF5MVRWTDlVQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==` + + caBytes, err := base64.StdEncoding.DecodeString(ca) + assert.Nil(t, err) + + expectedRootCAs := x509.NewCertPool() + expectedRootCAs.AppendCertsFromPEM(caBytes) + + //nolint:lll + crt := `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJNekNCNXFBREFnRUNBaEVBZ1BscnFYWUtDeVNHRkxmazVVK2JQekFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdPREV5TVRnek1UQTNXaGNOTXpJd09EQTVNVGd6TVRBM1dqQVRNUkV3RHdZRApWUVFLRXdodmN6cGhaRzFwYmpBcU1BVUdBeXRsY0FNaEFKblVxM1V1TzNTaGg4YW50eEZzNGJnZDlXeGRtcit6CmZURkxIcGpQVWlUaG8xSXdVREFPQmdOVkhROEJBZjhFQkFNQ0I0QXdIUVlEVlIwbEJCWXdGQVlJS3dZQkJRVUgKQXdFR0NDc0dBUVVGQndNQ01COEdBMVVkSXdRWU1CYUFGR09HaDRlMGE2aGJqWlVxN2ZKci9IY0owZUNRTUFVRwpBeXRsY0FOQkFNaW1wdnlxa0RHWDhROFErMTBtVWowYXJoQUpqdHl4OHErQll2QnlWOThxYyt3VldnYlFBc3FmClV3Sy9lN2ZLak1qMi9kRUZqOCs2SGZpOVJMTE5udzQ9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K` + + key := `LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJQ3FTdHpMTTNzaHNqMlZld2dXaVBPaDJUT01uUmM3cmNyRkczTGhNaFdkQQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K` + + keyBytes, err := base64.StdEncoding.DecodeString(key) + assert.Nil(t, err) + + crtBytes, err := base64.StdEncoding.DecodeString(crt) + assert.Nil(t, err) + + expectedCert, err := tls.X509KeyPair(crtBytes, keyBytes) + assert.Nil(t, err) + + expectedCerts := []tls.Certificate{expectedCert} + + t.Run("Returns default tls config for empty config context.", func(t *testing.T) { + // given + configContext := clientconfig.Context{} + + // when + tlsConfig, err := client.BuildTLSConfig(&configContext) + assert.Nil(t, err) + + // then + expected := &tls.Config{} + assert.Equal(t, expected, tlsConfig) + }) + + t.Run("Returns tls config with CA for config context with CA.", func(t *testing.T) { + // given + configContext := clientconfig.Context{ + CA: ca, + } + + // when + tlsConfig, err := client.BuildTLSConfig(&configContext) + assert.Nil(t, err) + + // then + assert.True(t, expectedRootCAs.Equal(tlsConfig.RootCAs)) + + assert.Len(t, tlsConfig.Certificates, 0) + }) + + t.Run("Returns tls config with Certificate for config context with Crt and Key.", func(t *testing.T) { + // given + configContext := clientconfig.Context{ + Crt: crt, + Key: key, + } + + // when + tlsConfig, err := client.BuildTLSConfig(&configContext) + assert.Nil(t, err) + + // then + assert.Equal(t, expectedCerts, tlsConfig.Certificates) + assert.Equal(t, tls.RequireAndVerifyClientCert, tlsConfig.ClientAuth) + + assert.Nil(t, tlsConfig.RootCAs) + }) + + t.Run("Returns tls config with CA and Certificate for config context with CA, Crt and Key.", func(t *testing.T) { + // given + configContext := clientconfig.Context{ + CA: ca, + Crt: crt, + Key: key, + } + + // when + tlsConfig, err := client.BuildTLSConfig(&configContext) + assert.Nil(t, err) + + // then + assert.True(t, expectedRootCAs.Equal(tlsConfig.RootCAs)) + + assert.Equal(t, expectedCerts, tlsConfig.Certificates) + assert.Equal(t, tls.RequireAndVerifyClientCert, tlsConfig.ClientAuth) + }) +} diff --git a/pkg/machinery/client/export_test.go b/pkg/machinery/client/export_test.go new file mode 100644 index 000000000..5a907a1a7 --- /dev/null +++ b/pkg/machinery/client/export_test.go @@ -0,0 +1,19 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package client + +import ( + "crypto/tls" + + clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config" +) + +func ReduceURLsToAddresses(endpoints []string) []string { + return reduceURLsToAddresses(endpoints) +} + +func BuildTLSConfig(configContext *clientconfig.Context) (*tls.Config, error) { + return buildTLSConfig(configContext) +} diff --git a/pkg/machinery/client/grpc_connection_wrapper.go b/pkg/machinery/client/grpc_connection_wrapper.go new file mode 100644 index 000000000..ea72f4f12 --- /dev/null +++ b/pkg/machinery/client/grpc_connection_wrapper.go @@ -0,0 +1,46 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package client + +import ( + "context" + + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +type grpcConnectionWrapper struct { + *grpc.ClientConn + + clusterName string +} + +func newGRPCConnectionWrapper(clusterName string, conn *grpc.ClientConn) *grpcConnectionWrapper { + return &grpcConnectionWrapper{ + ClientConn: conn, + clusterName: clusterName, + } +} + +// Invoke performs a unary RPC and returns after the response is received +// into reply. +func (c *grpcConnectionWrapper) Invoke(ctx context.Context, method string, args interface{}, reply interface{}, opts ...grpc.CallOption) error { + return c.ClientConn.Invoke(c.appendMetadata(ctx), method, args, reply, opts...) +} + +// NewStream begins a streaming RPC. +func (c *grpcConnectionWrapper) NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) { + return c.ClientConn.NewStream(c.appendMetadata(ctx), desc, method, opts...) +} + +func (c *grpcConnectionWrapper) appendMetadata(ctx context.Context) context.Context { + ctx = metadata.AppendToOutgoingContext(ctx, "runtime", "Talos") + + if c.clusterName != "" { + ctx = metadata.AppendToOutgoingContext(ctx, "context", c.clusterName) + } + + return ctx +} diff --git a/pkg/machinery/client/insecure_credentials.go b/pkg/machinery/client/insecure_credentials.go new file mode 100644 index 000000000..870abaeb6 --- /dev/null +++ b/pkg/machinery/client/insecure_credentials.go @@ -0,0 +1,47 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//go:build sidero.debug +// +build sidero.debug + +package client + +import ( + "net/url" + + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + + clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config" +) + +// shouldInsecureConnectionsBeAllowed returns true if one endpoint starts with http:// +func shouldInsecureConnectionsBeAllowed(endpoints []string) bool { + for _, endpoint := range endpoints { + u, _ := url.Parse(endpoint) + if u.Scheme == "http" { + return true + } + } + + return false +} + +// RequireTransportSecurity enables basic auth with insecure gRPC transport credentials. +func (c BasicAuth) RequireTransportSecurity() bool { + return false +} + +func buildCredentials(configContext *clientconfig.Context, endpoints []string) (credentials.TransportCredentials, error) { + if shouldInsecureConnectionsBeAllowed(endpoints) { + return insecure.NewCredentials(), nil + } + + tlsConfig, err := buildTLSConfig(configContext) + if err != nil { + return nil, err + } + + return credentials.NewTLS(tlsConfig), nil +} diff --git a/pkg/machinery/client/options.go b/pkg/machinery/client/options.go index 9e775a6c1..4461005a9 100644 --- a/pkg/machinery/client/options.go +++ b/pkg/machinery/client/options.go @@ -24,7 +24,8 @@ type Options struct { contextOverride string contextOverrideSet bool - unixSocketPath string + unixSocketPath string + clusterNameOverride string } // OptionFunc sets an option for the creation of the Client. @@ -123,3 +124,12 @@ func WithUnixSocket(path string) OptionFunc { return nil } } + +// WithCluster creates a Client which connects to the named cluster. +func WithCluster(cluster string) OptionFunc { + return func(o *Options) error { + o.clusterNameOverride = cluster + + return nil + } +} diff --git a/pkg/machinery/client/secure_credentials.go b/pkg/machinery/client/secure_credentials.go new file mode 100644 index 000000000..e0617d755 --- /dev/null +++ b/pkg/machinery/client/secure_credentials.go @@ -0,0 +1,28 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//go:build !sidero.debug +// +build !sidero.debug + +package client + +import ( + "google.golang.org/grpc/credentials" + + clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config" +) + +// RequireTransportSecurity implements credentials.PerRPCCredentials. +func (c BasicAuth) RequireTransportSecurity() bool { + return true +} + +func buildCredentials(configContext *clientconfig.Context, endpoints []string) (credentials.TransportCredentials, error) { + tlsConfig, err := buildTLSConfig(configContext) + if err != nil { + return nil, err + } + + return credentials.NewTLS(tlsConfig), nil +} diff --git a/pkg/machinery/config/types/v1alpha1/generate/generate_test.go b/pkg/machinery/config/types/v1alpha1/generate/generate_test.go index b0090968f..2ee328245 100644 --- a/pkg/machinery/config/types/v1alpha1/generate/generate_test.go +++ b/pkg/machinery/config/types/v1alpha1/generate/generate_test.go @@ -122,12 +122,12 @@ func (suite *GenerateSuite) TestGenerateTalosconfigSuccess() { cfg, err := genv1alpha1.Talosconfig(suite.input) suite.Require().NoError(err) - creds, err := client.CredentialsFromConfigContext(cfg.Contexts[cfg.Context]) + creds, err := client.CertificateFromConfigContext(cfg.Contexts[cfg.Context]) suite.Require().NoError(err) - suite.Require().Nil(creds.Crt.Leaf) - suite.Require().Len(creds.Crt.Certificate, 1) + suite.Require().Nil(creds.Leaf) + suite.Require().Len(creds.Certificate, 1) - cert, err := x509.ParseCertificate(creds.Crt.Certificate[0]) + cert, err := x509.ParseCertificate(creds.Certificate[0]) suite.Require().NoError(err) suite.Equal([]string{string(role.Admin)}, cert.Subject.Organization) diff --git a/website/content/v1.2/reference/cli.md b/website/content/v1.2/reference/cli.md index ab31a2d8d..c1128a9f1 100644 --- a/website/content/v1.2/reference/cli.md +++ b/website/content/v1.2/reference/cli.md @@ -29,6 +29,7 @@ talosctl apply-config [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -69,6 +70,7 @@ talosctl bootstrap [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -157,6 +159,7 @@ talosctl cluster create [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration --name string the name of the cluster (default "talos-default") @@ -187,6 +190,7 @@ talosctl cluster destroy [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration --name string the name of the cluster (default "talos-default") @@ -217,6 +221,7 @@ talosctl cluster show [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration --name string the name of the cluster (default "talos-default") @@ -246,6 +251,7 @@ A collection of commands for managing local docker-based or QEMU-based clusters ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -319,6 +325,7 @@ talosctl completion SHELL [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -349,6 +356,7 @@ talosctl config add [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -376,6 +384,7 @@ talosctl config context [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -403,6 +412,7 @@ talosctl config contexts [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -430,6 +440,7 @@ talosctl config endpoint ... [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -457,6 +468,7 @@ talosctl config info [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -488,6 +500,7 @@ talosctl config merge [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -517,6 +530,7 @@ talosctl config new [] [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -544,6 +558,7 @@ talosctl config node ... [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -567,6 +582,7 @@ Manage the client configuration file (talosconfig) ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -603,6 +619,7 @@ talosctl conformance kubernetes [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -626,6 +643,7 @@ Run conformance tests ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -655,6 +673,7 @@ talosctl containers [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -693,6 +712,7 @@ talosctl copy -| [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -737,6 +757,7 @@ talosctl dashboard [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -765,6 +786,7 @@ talosctl disks [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -794,6 +816,7 @@ talosctl dmesg [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -834,6 +857,7 @@ talosctl edit [] [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -861,6 +885,7 @@ talosctl etcd forfeit-leadership [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -888,6 +913,7 @@ talosctl etcd leave [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -915,6 +941,7 @@ talosctl etcd members [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -948,6 +975,7 @@ talosctl etcd remove-member [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -975,6 +1003,7 @@ talosctl etcd snapshot [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -998,6 +1027,7 @@ Manage etcd ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1034,6 +1064,7 @@ talosctl events [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1064,6 +1095,7 @@ talosctl gen ca [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1116,6 +1148,7 @@ talosctl gen config [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1147,6 +1180,7 @@ talosctl gen crt [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1177,6 +1211,7 @@ talosctl gen csr [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1205,6 +1240,7 @@ talosctl gen key [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1234,6 +1270,7 @@ talosctl gen keypair [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1265,6 +1302,7 @@ talosctl gen secrets [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1288,6 +1326,7 @@ Generate CAs, certificates, and private keys ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1331,6 +1370,7 @@ talosctl get [] [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1365,6 +1405,7 @@ talosctl health [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1392,6 +1433,7 @@ talosctl images [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1431,6 +1473,7 @@ cat deployment.yaml | talosctl inject serviceaccount --roles="os:admin" -f - > d ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1454,6 +1497,7 @@ Inject Talos API resources into Kubernetes manifests ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1493,6 +1537,7 @@ talosctl inspect dependencies [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1516,6 +1561,7 @@ Inspect internals of Talos ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1553,6 +1599,7 @@ talosctl kubeconfig [local-path] [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1588,6 +1635,7 @@ talosctl list [path] [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1618,6 +1666,7 @@ talosctl logs [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1646,6 +1695,7 @@ talosctl memory [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1673,6 +1723,7 @@ talosctl mounts [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1706,6 +1757,7 @@ talosctl patch [] [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1767,6 +1819,7 @@ talosctl pcap [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1796,6 +1849,7 @@ talosctl processes [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1823,6 +1877,7 @@ talosctl read [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1851,6 +1906,7 @@ talosctl reboot [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1881,6 +1937,7 @@ talosctl reset [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1909,6 +1966,7 @@ talosctl restart [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1936,6 +1994,7 @@ talosctl rollback [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1969,6 +2028,7 @@ talosctl service [ [start|stop|restart|status]] [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -1997,6 +2057,7 @@ talosctl shutdown [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -2025,6 +2086,7 @@ talosctl stats [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -2077,6 +2139,7 @@ talosctl support [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -2105,6 +2168,7 @@ talosctl time [--check server] [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -2136,6 +2200,7 @@ talosctl upgrade [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -2172,6 +2237,7 @@ talosctl upgrade-k8s [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -2203,6 +2269,7 @@ talosctl usage [path1] [path2] ... [pathN] [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -2233,6 +2300,7 @@ talosctl validate [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -2263,6 +2331,7 @@ talosctl version [flags] ### Options inherited from parent commands ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -n, --nodes strings target the specified nodes @@ -2280,6 +2349,7 @@ A CLI for out-of-band management of Kubernetes nodes created by Talos ### Options ``` + --cluster string Cluster to connect to if a proxy endpoint is used. --context string Context to be used in command -e, --endpoints strings override default endpoints in Talos configuration -h, --help help for talosctl