feat: implement talosctl config new command

Refs #3421.

Signed-off-by: Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
This commit is contained in:
Alexey Palazhchenko
2021-06-15 18:47:54 +00:00
committed by talos-bot
parent fa15a6687f
commit f63ab9dd9b
61 changed files with 2340 additions and 1726 deletions

View File

@ -5,7 +5,6 @@
!hack
!internal
!pkg
!vendor
!website
!.golangci.yml
!.markdownlint.json

View File

@ -3,9 +3,6 @@ syntax = "proto3";
package cluster;
option go_package = "github.com/talos-systems/talos/pkg/machinery/api/cluster";
option java_multiple_files = true;
option java_outer_classname = "ClusterApi";
option java_package = "com.cluster.api";
import "google/protobuf/duration.proto";
import "common/common.proto";

View File

@ -6,6 +6,7 @@ option go_package = "github.com/talos-systems/talos/pkg/machinery/api/health";
import "google/protobuf/empty.proto";
// The health service definition.
service Health {
rpc Check(google.protobuf.Empty) returns (HealthCheckResponse);
rpc Watch(HealthWatchRequest) returns (stream HealthCheckResponse);

View File

@ -3,9 +3,6 @@ syntax = "proto3";
package inspect;
option go_package = "github.com/talos-systems/talos/pkg/machinery/api/inspect";
option java_multiple_files = true;
option java_outer_classname = "InspectApi";
option java_package = "com.inspect.api";
import "google/protobuf/empty.proto";
import "common/common.proto";

View File

@ -3,13 +3,11 @@ syntax = "proto3";
package machine;
option go_package = "github.com/talos-systems/talos/pkg/machinery/api/machine";
option java_multiple_files = true;
option java_outer_classname = "MachineApi";
option java_package = "com.machine.api";
import "google/protobuf/any.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";
import "common/common.proto";
// The machine service definition.
@ -82,6 +80,9 @@ service MachineService {
rpc SystemStat(google.protobuf.Empty) returns (SystemStatResponse);
rpc Upgrade(UpgradeRequest) returns (UpgradeResponse);
rpc Version(google.protobuf.Empty) returns (VersionResponse);
// GenerateClientConfiguration generates talosctl client configuration (talosconfig).
rpc GenerateClientConfiguration(GenerateClientConfigurationRequest) returns (GenerateClientConfigurationResponse);
}
// rpc applyConfiguration
@ -486,8 +487,6 @@ message DmesgRequest {
}
// rpc processes
message ProcessesRequest {}
message ProcessesResponse { repeated Process messages = 1; }
message Process {
@ -910,3 +909,26 @@ message GenerateConfigurationResponse {
// RemoveBootkubeInitializedKeyResponse describes the response to a RemoveBootkubeInitializedKey request.
message RemoveBootkubeInitializedKey { common.Metadata metadata = 1; }
message RemoveBootkubeInitializedKeyResponse { repeated RemoveBootkubeInitializedKey messages = 1; }
message GenerateClientConfigurationRequest {
// Roles in the generated client certificate.
repeated string roles = 1;
// Client certificate TTL.
google.protobuf.Duration crt_ttl = 2;
}
message GenerateClientConfiguration {
common.Metadata metadata = 1;
// PEM-encoded CA certificate.
bytes ca = 2;
// PEM-encoded generated client certificate.
bytes crt = 3;
// PEM-encoded generated client key.
bytes key = 4;
// Client configuration (talosconfig) file content.
bytes talosconfig = 5;
}
message GenerateClientConfigurationResponse {
repeated GenerateClientConfiguration messages = 1;
}

View File

@ -3,9 +3,6 @@ syntax = "proto3";
package network;
option go_package = "github.com/talos-systems/talos/pkg/machinery/api/network";
option java_multiple_files = true;
option java_outer_classname = "NetworkApi";
option java_package = "com.network.api";
import "google/protobuf/empty.proto";
import "common/common.proto";

View File

@ -3,9 +3,6 @@ syntax = "proto3";
package resource;
option go_package = "github.com/talos-systems/talos/pkg/machinery/api/resource";
option java_multiple_files = true;
option java_outer_classname = "ResourceApi";
option java_package = "com.resource.api";
import "common/common.proto";

View File

@ -3,9 +3,6 @@ syntax = "proto3";
package securityapi;
option go_package = "github.com/talos-systems/talos/pkg/machinery/api/security";
option java_multiple_files = true;
option java_outer_classname = "SecurityApi";
option java_package = "com.security.api";
// The security service definition.
service SecurityService {

View File

@ -3,9 +3,6 @@ syntax = "proto3";
package storage;
option go_package = "github.com/talos-systems/talos/pkg/machinery/api/storage";
option java_multiple_files = true;
option java_outer_classname = "StorageApi";
option java_package = "com.storage.api";
import "google/protobuf/empty.proto";
import "common/common.proto";

View File

@ -3,9 +3,6 @@ syntax = "proto3";
package time;
option go_package = "github.com/talos-systems/talos/pkg/machinery/api/time";
option java_multiple_files = true;
option java_outer_classname = "TimeApi";
option java_package = "com.time.api";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";

View File

@ -55,9 +55,9 @@ var genCSRCmd = &cobra.Command{
return fmt.Errorf("invalid IP: %s", genCSRCmdFlags.ip)
}
roles, err := role.Parse(genCSRCmdFlags.roles)
if err != nil {
return err
roles, unknownRoles := role.Parse(genCSRCmdFlags.roles)
if len(unknownRoles) != 0 {
return fmt.Errorf("unknown roles: %s", strings.Join(unknownRoles, ", "))
}
ips := []net.IP{parsed}

View File

@ -13,7 +13,7 @@ import (
"github.com/talos-systems/talos/cmd/talosctl/cmd/mgmt"
"github.com/talos-systems/talos/cmd/talosctl/cmd/talos"
"github.com/talos-systems/talos/pkg/machinery/client/config"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
)
// rootCmd represents the base command when called without any subcommands.
@ -29,7 +29,7 @@ var rootCmd = &cobra.Command{
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() error {
defaultTalosConfig, err := config.GetDefaultPath()
defaultTalosConfig, err := clientconfig.GetDefaultPath()
if err != nil {
return err
}

View File

@ -14,6 +14,7 @@ import (
"github.com/spf13/cobra"
"github.com/talos-systems/crypto/x509"
"github.com/talos-systems/talos/cmd/talosctl/pkg/talos/helpers"
"github.com/talos-systems/talos/internal/pkg/tui/installer"
"github.com/talos-systems/talos/pkg/cli"
machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine"
@ -71,8 +72,8 @@ var applyConfigCmd = &cobra.Command{
if applyConfigCmdFlags.insecure {
ctx := context.Background()
if len(Nodes) != 1 {
return fmt.Errorf("insecure mode requires one and only one node, got %d", len(Nodes))
if err := helpers.FailIfMultiNodes(ctx, "apply-config"); err != nil {
return err
}
c, err := client.New(ctx, client.WithTLSConfig(&tls.Config{

View File

@ -5,6 +5,7 @@
package talos
import (
"context"
"encoding/base64"
"fmt"
"io/ioutil"
@ -12,27 +13,48 @@ import (
"sort"
"strings"
"text/tabwriter"
"time"
"github.com/spf13/cobra"
"google.golang.org/protobuf/types/known/durationpb"
"github.com/talos-systems/talos/cmd/talosctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine"
"github.com/talos-systems/talos/pkg/machinery/client"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
)
var (
ca string
crt string
key string
"github.com/talos-systems/talos/pkg/machinery/role"
)
// configCmd represents the config command.
var configCmd = &cobra.Command{
Use: "config",
Short: "Manage the client configuration",
Short: "Manage the client configuration file (talosconfig)",
Long: ``,
}
// configEndpointCmd represents the config endpoint command.
func openConfigAndContext(context string) (*clientconfig.Config, error) {
c, err := clientconfig.Open(Talosconfig)
if err != nil {
return nil, fmt.Errorf("error reading config: %w", err)
}
if context == "" {
context = c.Context
}
if context == "" {
return nil, fmt.Errorf("no context is set")
}
if _, ok := c.Contexts[context]; !ok {
return nil, fmt.Errorf("context %q is not defined", context)
}
return c, nil
}
// configEndpointCmd represents the `config endpoint` command.
var configEndpointCmd = &cobra.Command{
Use: "endpoint <endpoint>...",
Aliases: []string{"endpoints"},
@ -58,7 +80,7 @@ var configEndpointCmd = &cobra.Command{
},
}
// configNodeCmd represents the config node command.
// configNodeCmd represents the `config node` command.
var configNodeCmd = &cobra.Command{
Use: "node <endpoint>...",
Aliases: []string{"nodes"},
@ -84,7 +106,7 @@ var configNodeCmd = &cobra.Command{
},
}
// configContextCmd represents the config context command.
// configContextCmd represents the `config context` command.
var configContextCmd = &cobra.Command{
Use: "context <context>",
Short: "Set the current context",
@ -109,7 +131,14 @@ var configContextCmd = &cobra.Command{
},
}
// configAddCmd represents the config add command.
// configAddCmdFlags represents the `config add` command flags.
var configAddCmdFlags struct {
ca string
crt string
key string
}
// configAddCmd represents the `config add` command.
var configAddCmd = &cobra.Command{
Use: "add <context>",
Short: "Add a new context",
@ -122,17 +151,17 @@ var configAddCmd = &cobra.Command{
return fmt.Errorf("error reading config: %w", err)
}
caBytes, err := ioutil.ReadFile(ca)
caBytes, err := ioutil.ReadFile(configAddCmdFlags.ca)
if err != nil {
return fmt.Errorf("error reading CA: %w", err)
}
crtBytes, err := ioutil.ReadFile(crt)
crtBytes, err := ioutil.ReadFile(configAddCmdFlags.crt)
if err != nil {
return fmt.Errorf("error reading certificate: %w", err)
}
keyBytes, err := ioutil.ReadFile(key)
keyBytes, err := ioutil.ReadFile(configAddCmdFlags.key)
if err != nil {
return fmt.Errorf("error reading key: %w", err)
}
@ -156,45 +185,12 @@ var configAddCmd = &cobra.Command{
},
}
// configGenerateCmd represents the config generate stub command.
var configGenerateCmd = &cobra.Command{
Use: "generate",
Short: "Generate Talos config",
Long: ``,
Hidden: true,
RunE: func(cmd *cobra.Command, args []string) error {
return fmt.Errorf("'talosctl config generate' was renamed to 'talosctl gen config'")
},
}
func openConfigAndContext(context string) (*clientconfig.Config, error) {
c, err := clientconfig.Open(Talosconfig)
if err != nil {
return nil, fmt.Errorf("error reading config: %w", err)
}
if context == "" {
context = c.Context
}
if context == "" {
return nil, fmt.Errorf("no context is set")
}
if _, ok := c.Contexts[context]; !ok {
return nil, fmt.Errorf("context %q is not defined", context)
}
return c, nil
}
// configGetContexts represents config contexts command.
var configGetContexts = &cobra.Command{
// configGetContextsCmd represents the `config contexts` command.
var configGetContextsCmd = &cobra.Command{
Use: "contexts",
Short: "List contexts defined in Talos config",
Short: "List defined contexts",
Aliases: []string{"get-contexts"},
Long: ``,
Hidden: false,
RunE: func(cmd *cobra.Command, args []string) error {
c, err := clientconfig.Open(Talosconfig)
if err != nil {
@ -239,13 +235,12 @@ var configGetContexts = &cobra.Command{
},
}
// configMergeCmd represents the config merge command.
// configMergeCmd represents the `config merge` command.
var configMergeCmd = &cobra.Command{
Use: "merge <from>",
Short: "Merge additional contexts from another Talos config into the default config",
Long: "Contexts with the same name are renamed while merging configs.",
Hidden: false,
Args: cobra.MinimumNArgs(1),
Use: "merge <from>",
Short: "Merge additional contexts from another client configuration file",
Long: "Contexts with the same name are renamed while merging configs.",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
from := args[0]
c, err := clientconfig.Open(Talosconfig)
@ -271,13 +266,80 @@ var configMergeCmd = &cobra.Command{
},
}
// configNewCmdFlags represents the `config new` command flags.
var configNewCmdFlags struct {
roles []string
crtTTL time.Duration
}
// configNewCmd represents the `config new` command.
var configNewCmd = &cobra.Command{
Use: "new [<path>]",
Short: "Generate a new client configuration file",
Args: cobra.RangeArgs(0, 1),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
args = []string{"talosconfig"}
}
path := args[0]
return WithClient(func(ctx context.Context, c *client.Client) error {
if err := helpers.FailIfMultiNodes(ctx, "talosconfig"); err != nil {
return err
}
roles, unknownRoles := role.Parse(configNewCmdFlags.roles)
if len(unknownRoles) != 0 {
return fmt.Errorf("unknown roles: %s", strings.Join(unknownRoles, ", "))
}
if _, err := os.Stat(path); err == nil {
return fmt.Errorf("talosconfig file already exists: %q", path)
}
resp, err := c.GenerateClientConfiguration(ctx, &machineapi.GenerateClientConfigurationRequest{
Roles: roles.Strings(),
CrtTtl: durationpb.New(configNewCmdFlags.crtTTL),
})
if err != nil {
return err
}
if l := len(resp.Messages); l != 1 {
panic(fmt.Sprintf("expected 1 message, got %d", l))
}
config, err := clientconfig.FromBytes(resp.Messages[0].Talosconfig)
if err != nil {
return err
}
return config.Save(path)
})
},
}
func init() {
configCmd.AddCommand(configContextCmd, configEndpointCmd, configNodeCmd, configAddCmd, configGenerateCmd, configMergeCmd, configGetContexts)
configAddCmd.Flags().StringVar(&ca, "ca", "", "the path to the CA certificate")
configAddCmd.Flags().StringVar(&crt, "crt", "", "the path to the certificate")
configAddCmd.Flags().StringVar(&key, "key", "", "the path to the key")
configCmd.AddCommand(
configEndpointCmd,
configNodeCmd,
configContextCmd,
configAddCmd,
configGetContextsCmd,
configMergeCmd,
configNewCmd,
)
configAddCmd.Flags().StringVar(&configAddCmdFlags.ca, "ca", "", "the path to the CA certificate")
configAddCmd.Flags().StringVar(&configAddCmdFlags.crt, "crt", "", "the path to the certificate")
configAddCmd.Flags().StringVar(&configAddCmdFlags.key, "key", "", "the path to the key")
cli.Should(configAddCmd.MarkFlagRequired("ca"))
cli.Should(configAddCmd.MarkFlagRequired("crt"))
cli.Should(configAddCmd.MarkFlagRequired("key"))
configNewCmd.Flags().StringSliceVar(&configNewCmdFlags.roles, "roles", role.MakeSet(role.Admin).Strings(), "roles")
configNewCmd.Flags().DurationVar(&configNewCmdFlags.crtTTL, "crt-ttl", 87600*time.Hour, "certificate TTL")
addCommand(configCmd)
}

View File

@ -12,7 +12,7 @@ import (
"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/machinery/client"
"github.com/talos-systems/talos/pkg/machinery/client/config"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
)
var kubernetes bool
@ -30,7 +30,7 @@ var (
// WithClientNoNodes doesn't set any node information on request context.
func WithClientNoNodes(action func(context.Context, *client.Client) error) error {
return cli.WithContext(context.Background(), func(ctx context.Context) error {
cfg, err := config.Open(Talosconfig)
cfg, err := clientconfig.Open(Talosconfig)
if err != nil {
return fmt.Errorf("failed to open config file %q: %w", Talosconfig, err)
}

2
go.mod
View File

@ -77,7 +77,7 @@ require (
github.com/spf13/cobra v1.1.3
github.com/spf13/viper v1.7.1 // indirect
github.com/stretchr/testify v1.7.0
github.com/talos-systems/crypto v0.2.1-0.20210601174604-cd18ef62eb9f
github.com/talos-systems/crypto v0.3.1-0.20210615131117-6bc5bb50c527
github.com/talos-systems/go-blockdevice v0.2.1-0.20210526155905-30c2bc3cb62a
github.com/talos-systems/go-cmd v0.0.0-20210216164758-68eb0067e0f0
github.com/talos-systems/go-debug v0.2.1-0.20210525175311-3d0a6e1bf5e3

4
go.sum
View File

@ -1111,8 +1111,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/talos-systems/crypto v0.2.1-0.20210601174604-cd18ef62eb9f h1:Xk3zeUZPhvEl9Vs4PlYBohin3QZmizA/YR4URKEyULY=
github.com/talos-systems/crypto v0.2.1-0.20210601174604-cd18ef62eb9f/go.mod h1:xaNCB2/Bxaj+qrkdeodhRv5eKQVvKOGBBMj58MrIPY8=
github.com/talos-systems/crypto v0.3.1-0.20210615131117-6bc5bb50c527 h1:Ut3jI/0FPSyH0QpycKFKAueWKjzQ00OFmkeFG+0uO1A=
github.com/talos-systems/crypto v0.3.1-0.20210615131117-6bc5bb50c527/go.mod h1:xaNCB2/Bxaj+qrkdeodhRv5eKQVvKOGBBMj58MrIPY8=
github.com/talos-systems/go-blockdevice v0.2.1-0.20210526155905-30c2bc3cb62a h1:NLuIVKi5tBnRMgxk185AVGmMUzlRcggb2Abrw9uUq3E=
github.com/talos-systems/go-blockdevice v0.2.1-0.20210526155905-30c2bc3cb62a/go.mod h1:qnn/zDc09I1DA2BUDDCOSA2D0P8pIDjN8pGiRoRaQig=
github.com/talos-systems/go-cmd v0.0.0-20210216164758-68eb0067e0f0 h1:DI+BjK+fcrLBc70Fi50dZocQcaHosqsuWHrGHKp2NzE=

View File

@ -28,15 +28,23 @@ import (
"github.com/talos-systems/talos/pkg/startup"
)
const (
debugAddr = ":9981"
)
var (
endpoints *string
useK8sEndpoints *bool
)
func runDebugServer(ctx context.Context) {
const debugAddr = ":9981"
debugLogFunc := func(msg string) {
log.Print(msg)
}
if err := debug.ListenAndServe(ctx, debugAddr, debugLogFunc); err != nil {
log.Fatalf("failed to start debug server: %s", err)
}
}
// Main is the entrypoint of apid.
func Main() {
log.SetFlags(log.Lshortfile | log.Ldate | log.Lmicroseconds | log.Ltime)
@ -46,14 +54,7 @@ func Main() {
flag.Parse()
go func() {
debugLogFunc := func(msg string) {
log.Print(msg)
}
if lErr := debug.ListenAndServe(context.TODO(), debugAddr, debugLogFunc); lErr != nil {
log.Fatalf("failed to start debug server: %s", lErr)
}
}()
go runDebugServer(context.TODO())
if err := startup.RandSeed(); err != nil {
log.Fatalf("failed to seed RNG: %v", err)
@ -119,9 +120,14 @@ func Main() {
var errGroup errgroup.Group
errGroup.Go(func() error {
mode := authz.Disabled
if config.Machine().Features().RBACEnabled() {
mode = authz.Enabled
}
injector := &authz.Injector{
TrustMetadata: false,
Logger: log.New(log.Writer(), "apid/authz/injector/http ", log.Flags()).Printf,
Mode: mode,
Logger: log.New(log.Writer(), "apid/authz/injector/http ", log.Flags()).Printf,
}
return factory.ListenAndServe(
@ -146,8 +152,8 @@ func Main() {
errGroup.Go(func() error {
injector := &authz.Injector{
TrustMetadata: true,
Logger: log.New(log.Writer(), "apid/authz/injector/unix ", log.Flags()).Printf,
Mode: authz.MetadataOnly,
Logger: log.New(log.Writer(), "apid/authz/injector/unix ", log.Flags()).Printf,
}
return factory.ListenAndServe(

View File

@ -54,7 +54,7 @@ func (a *APID) String() string {
// GetConnection returns a grpc connection to the backend.
func (a *APID) GetConnection(ctx context.Context) (context.Context, *grpc.ClientConn, error) {
md, _ := metadata.FromIncomingContext(ctx)
md = metadata.Join(md, authz.RolesAsMetadata(authz.GetRoles(ctx)))
md = metadata.Join(md, authz.RolesAsMetadata(authz.GetRoles(ctx))) // TODO(rbac): duplicates?
if authority := md[":authority"]; len(authority) > 0 {
md.Set("proxyfrom", authority...)

View File

@ -16,7 +16,9 @@ import (
"google.golang.org/grpc/status"
"gopkg.in/yaml.v3"
"github.com/talos-systems/talos/pkg/grpc/middleware/authz"
resourceapi "github.com/talos-systems/talos/pkg/machinery/api/resource"
"github.com/talos-systems/talos/pkg/machinery/role"
)
// ResourceServer implements ResourceService API.
@ -118,6 +120,15 @@ func (s *ResourceServer) resolveResourceKind(ctx context.Context, kind *resource
}
func (s *ResourceServer) checkReadAccess(ctx context.Context, kind *resourceKind) error {
roles := authz.GetRoles(ctx)
// TODO(rbac): check sensitivity levels once they are added to COSI
if strings.Contains(kind.Type, "secret") {
if !roles.Includes(role.Admin) {
return authz.ErrNotAuthorized
}
}
registeredNamespaces, err := s.server.Controller.Runtime().State().V1Alpha2().Resources().List(ctx, resource.NewMetadata(meta.NamespaceName, meta.NamespaceType, "", resource.VersionUndefined))
if err != nil {
return err

View File

@ -38,6 +38,8 @@ import (
"go.etcd.io/etcd/client/v3/concurrency"
"golang.org/x/sys/unix"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
installer "github.com/talos-systems/talos/cmd/installer/pkg/install"
"github.com/talos-systems/talos/internal/app/machined/internal/install"
@ -68,9 +70,12 @@ import (
"github.com/talos-systems/talos/pkg/machinery/api/resource"
"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/config"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/generate"
machinetype "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine"
"github.com/talos-systems/talos/pkg/machinery/constants"
"github.com/talos-systems/talos/pkg/machinery/role"
"github.com/talos-systems/talos/pkg/version"
)
@ -1916,6 +1921,53 @@ func (s *Server) RemoveBootkubeInitializedKey(ctx context.Context, in *empty.Emp
}, nil
}
// GenerateClientConfiguration implements the machine.MachineServer interface.
func (s *Server) GenerateClientConfiguration(ctx context.Context, in *machine.GenerateClientConfigurationRequest) (*machine.GenerateClientConfigurationResponse, error) {
if s.Controller.Runtime().Config().Machine().Type() == machinetype.TypeJoin {
return nil, status.Error(codes.FailedPrecondition, "client configuration (talosconfig) can't be generated on worker nodes")
}
crtTTL := in.CrtTtl.AsDuration()
if crtTTL <= 0 {
return nil, status.Error(codes.InvalidArgument, "crt_ttl should be positive")
}
ca := s.Controller.Runtime().Config().Machine().Security().CA()
roles, _ := role.Parse(in.Roles)
cert, err := generate.NewAdminCertificateAndKey(time.Now(), ca, roles, crtTTL)
if err != nil {
return nil, err
}
// make a nice context name
contextName := s.Controller.Runtime().Config().Cluster().Name()
if r := roles.Strings(); len(r) == 1 {
contextName = strings.TrimPrefix(r[0], role.Prefix) + "@" + contextName
}
talosconfig := clientconfig.NewConfig(contextName, nil, ca.Crt, cert)
b, err := talosconfig.Bytes()
if err != nil {
return nil, err
}
reply := &machine.GenerateClientConfigurationResponse{
Messages: []*machine.GenerateClientConfiguration{
{
Ca: ca.Crt,
Crt: cert.Crt,
Key: cert.Key,
Talosconfig: b,
},
},
}
return reply, nil
}
func upgradeMutex(c *etcd.Client) (*concurrency.Mutex, error) {
sess, err := concurrency.NewSession(c.Client,
concurrency.WithTTL(MinimumEtcdUpgradeLeaseLockSeconds),

View File

@ -38,10 +38,6 @@ import (
"github.com/talos-systems/talos/pkg/startup"
)
const (
debugAddr = ":9982"
)
func init() {
// Explicitly set the default http client transport to work around proxy.Do
// once. This is the http.DefaultTransport with the Proxy func overridden so
@ -178,6 +174,18 @@ func handle(err error) {
}
}
func runDebugServer(ctx context.Context) {
const debugAddr = ":9982"
debugLogFunc := func(msg string) {
log.Print(msg)
}
if err := debug.ListenAndServe(ctx, debugAddr, debugLogFunc); err != nil {
log.Fatalf("failed to start debug server: %s", err)
}
}
//nolint:gocyclo
func run() error {
errCh := make(chan error)
@ -201,14 +209,7 @@ func run() error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
debugLogFunc := func(msg string) {
log.Print(msg)
}
if lErr := debug.ListenAndServe(ctx, debugAddr, debugLogFunc); lErr != nil {
log.Fatalf("failed to start debug server: %s", lErr)
}
}()
go runDebugServer(ctx)
// Schedule service shutdown on any return.
defer system.Services(c.Runtime()).Shutdown(ctx)

View File

@ -29,20 +29,24 @@ type machinedService struct {
// Main is an entrypoint the the API service.
func (s *machinedService) Main(ctx context.Context, r runtime.Runtime, logWriter io.Writer) error {
injector := &authz.Injector{
TrustMetadata: true,
Logger: log.New(logWriter, "machined/authz/injector ", log.Flags()).Printf,
Mode: authz.MetadataOnly,
Logger: log.New(logWriter, "machined/authz/injector ", log.Flags()).Printf,
}
authorizer := &authz.Authorizer{
Rules: map[string]role.Set{
"/machine.MachineService/GenerateClientConfiguration": role.MakeSet(role.Admin),
"/cluster.ClusterService/HealthCheck": role.MakeSet(role.Admin, role.Reader),
"/machine.MachineService/List": role.MakeSet(role.Admin, role.Reader),
"/machine.MachineService/Version": role.MakeSet(role.Admin, role.Reader),
// per-type authorization is handled by the service itself
"/resource.ResourceService": role.MakeSet(role.Admin, role.Reader),
// TODO(rbac): More rules
},
FallbackRoles: role.MakeSet(role.Admin),
Enforce: r.Config().Machine().Features().RBACEnabled(),
Logger: log.New(logWriter, "machined/authz/authorizer ", log.Flags()).Printf,
}

View File

@ -10,6 +10,8 @@ import (
"log"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
networkserver "github.com/talos-systems/talos/internal/app/networkd/pkg/server"
@ -51,7 +53,7 @@ func (s *Server) Register(obj *grpc.Server) {
}
// ApplyConfiguration implements machine.MachineService.
func (s *Server) ApplyConfiguration(ctx context.Context, in *machine.ApplyConfigurationRequest) (reply *machine.ApplyConfigurationResponse, err error) {
func (s *Server) ApplyConfiguration(ctx context.Context, in *machine.ApplyConfigurationRequest) (*machine.ApplyConfigurationResponse, error) {
if in.OnReboot {
return nil, fmt.Errorf("apply configuration on reboot is not supported in maintenance mode")
}
@ -66,7 +68,7 @@ func (s *Server) ApplyConfiguration(ctx context.Context, in *machine.ApplyConfig
return nil, fmt.Errorf("configuration validation failed: %w", err)
}
reply = &machine.ApplyConfigurationResponse{
reply := &machine.ApplyConfigurationResponse{
Messages: []*machine.ApplyConfiguration{
{
Warnings: warnings,
@ -80,7 +82,7 @@ func (s *Server) ApplyConfiguration(ctx context.Context, in *machine.ApplyConfig
}
// GenerateConfiguration implements the machine.MachineServer interface.
func (s *Server) GenerateConfiguration(ctx context.Context, in *machine.GenerateConfigurationRequest) (reply *machine.GenerateConfigurationResponse, err error) {
func (s *Server) GenerateConfiguration(ctx context.Context, in *machine.GenerateConfigurationRequest) (*machine.GenerateConfigurationResponse, error) {
if in.MachineConfig == nil {
return nil, fmt.Errorf("invalid generate request")
}
@ -88,8 +90,13 @@ func (s *Server) GenerateConfiguration(ctx context.Context, in *machine.Generate
machineType := v1alpha1machine.Type(in.MachineConfig.Type)
if machineType == v1alpha1machine.TypeJoin {
return nil, fmt.Errorf("join config cannot be generated in the maintenance mode")
return nil, fmt.Errorf("join config can't be generated in the maintenance mode")
}
return configuration.Generate(ctx, in)
}
// GenerateClientConfiguration implements the machine.MachineServer interface.
func (s *Server) GenerateClientConfiguration(ctx context.Context, in *machine.GenerateClientConfigurationRequest) (*machine.GenerateClientConfigurationResponse, error) {
return nil, status.Error(codes.Unimplemented, "client configuration (talosconfig) can't be generated in the maintenance mode")
}

View File

@ -26,9 +26,17 @@ import (
"github.com/talos-systems/talos/pkg/startup"
)
const (
debugAddr = ":9983"
)
func runDebugServer(ctx context.Context) {
const debugAddr = ":9983"
debugLogFunc := func(msg string) {
log.Print(msg)
}
if err := debug.ListenAndServe(ctx, debugAddr, debugLogFunc); err != nil {
log.Fatalf("failed to start debug server: %s", err)
}
}
// Main is the entrypoint into trustd.
//
@ -38,14 +46,7 @@ func Main() {
flag.Parse()
go func() {
debugLogFunc := func(msg string) {
log.Print(msg)
}
if lErr := debug.ListenAndServe(context.TODO(), debugAddr, debugLogFunc); lErr != nil {
log.Fatalf("failed to start debug server: %s", lErr)
}
}()
go runDebugServer(context.TODO())
var err error

View File

@ -26,7 +26,7 @@ import (
"github.com/talos-systems/talos/pkg/cluster/check"
machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine"
"github.com/talos-systems/talos/pkg/machinery/client"
"github.com/talos-systems/talos/pkg/machinery/client/config"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine"
"github.com/talos-systems/talos/pkg/provision"
"github.com/talos-systems/talos/pkg/provision/access"
@ -42,7 +42,7 @@ type APISuite struct {
// SetupSuite initializes Talos API client.
func (apiSuite *APISuite) SetupSuite() {
cfg, err := config.Open(apiSuite.TalosConfig)
cfg, err := clientconfig.Open(apiSuite.TalosConfig)
apiSuite.Require().NoError(err)
opts := []client.OptionFunc{

View File

@ -21,7 +21,7 @@ import (
"github.com/talos-systems/talos/internal/integration/cli"
"github.com/talos-systems/talos/internal/integration/k8s"
provision_test "github.com/talos-systems/talos/internal/integration/provision"
"github.com/talos-systems/talos/pkg/machinery/client/config"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
"github.com/talos-systems/talos/pkg/provision"
"github.com/talos-systems/talos/pkg/provision/providers"
"github.com/talos-systems/talos/pkg/version"
@ -116,9 +116,9 @@ func TestIntegration(t *testing.T) {
}
func init() {
defaultTalosConfig, _ := config.GetDefaultPath() //nolint:errcheck
defaultTalosConfig, _ := clientconfig.GetDefaultPath() //nolint:errcheck
defaultStateDir, err := config.GetTalosDirectory()
defaultStateDir, err := clientconfig.GetTalosDirectory()
if err == nil {
defaultStateDir = filepath.Join(defaultStateDir, "clusters")
}

View File

@ -45,7 +45,7 @@ func GeneratePeerCert(etcdCA *x509.PEMEncodedCertificateAndKey) (*x509.PEMEncode
x509.NotAfter(time.Now().Add(87600 * time.Hour)),
}
ca, err := x509.NewCertificateAuthorityFromCertificateAndKey(etcdCA, opts...)
ca, err := x509.NewCertificateAuthorityFromCertificateAndKey(etcdCA)
if err != nil {
return nil, fmt.Errorf("failed loading CA from config: %w", err)
}

View File

@ -9,7 +9,7 @@ import (
"strings"
"github.com/talos-systems/talos/pkg/machinery/client"
"github.com/talos-systems/talos/pkg/machinery/client/config"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
)
// ConfigClientProvider builds Talos client from client config.
@ -20,7 +20,7 @@ type ConfigClientProvider struct {
DefaultClient *client.Client
// TalosConfig is a client Talos configuration.
TalosConfig *config.Config
TalosConfig *clientconfig.Config
clients map[string]*client.Client
}

View File

@ -8,7 +8,6 @@ import (
"context"
"strings"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@ -16,6 +15,9 @@ import (
"github.com/talos-systems/talos/pkg/machinery/role"
)
// ErrNotAuthorized should be returned to the client when they are not authorized.
var ErrNotAuthorized = status.Error(codes.PermissionDenied, "not authorized")
// Authorizer checks that the user is authorized (has a valid role) to call intercepted gRPC method.
// User roles should be set the Injector interceptor.
type Authorizer struct {
@ -25,9 +27,6 @@ type Authorizer struct {
// Defines roles for gRPC methods not present in Rules.
FallbackRoles role.Set
// If false, makes the authorizer never return authorization error.
Enforce bool
// Logger.
Logger func(format string, v ...interface{})
}
@ -56,21 +55,25 @@ func (a *Authorizer) logf(format string, v ...interface{}) {
// authorize returns error if the user is not authorized (doesn't have a valid role) to call the given gRPC method.
// User roles should be previously set the Injector interceptor.
func (a *Authorizer) authorize(ctx context.Context, method string) (context.Context, error) {
func (a *Authorizer) authorize(ctx context.Context, method string) error {
clientRoles := GetRoles(ctx)
var allowedRoles role.Set
var (
allowedRoles role.Set
found bool
)
prefix := method
for prefix != "/" {
if allowedRoles = a.Rules[prefix]; allowedRoles != nil {
allowedRoles, found = a.Rules[prefix]
if found {
break
}
prefix = nextPrefix(prefix)
}
if allowedRoles == nil {
if !found {
a.logf("no explicit rule found for %q, falling back to %v", method, a.FallbackRoles.Strings())
allowedRoles = a.FallbackRoles
}
@ -78,25 +81,18 @@ func (a *Authorizer) authorize(ctx context.Context, method string) (context.Cont
if allowedRoles.IncludesAny(clientRoles) {
a.logf("authorized (%v includes %v)", allowedRoles.Strings(), clientRoles.Strings())
return ctx, nil
}
if !a.Enforce {
a.logf("not authorized (%v doesn't include %v), but authorization wasn't enforced", allowedRoles.Strings(), clientRoles.Strings())
return ctx, nil
return nil
}
a.logf("not authorized (%v doesn't include %v)", allowedRoles.Strings(), clientRoles.Strings())
return nil, status.Error(codes.PermissionDenied, "not authorized")
return ErrNotAuthorized
}
// UnaryInterceptor returns grpc UnaryServerInterceptor.
func (a *Authorizer) UnaryInterceptor() grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
ctx, err := a.authorize(ctx, info.FullMethod)
if err != nil {
if err := a.authorize(ctx, info.FullMethod); err != nil {
return nil, err
}
@ -107,14 +103,10 @@ func (a *Authorizer) UnaryInterceptor() grpc.UnaryServerInterceptor {
// StreamInterceptor returns grpc StreamServerInterceptor.
func (a *Authorizer) StreamInterceptor() grpc.StreamServerInterceptor {
return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
ctx, err := a.authorize(stream.Context(), info.FullMethod)
if err != nil {
if err := a.authorize(stream.Context(), info.FullMethod); err != nil {
return err
}
wrapped := grpc_middleware.WrapServerStream(stream)
wrapped.WrappedContext = ctx
return handler(srv, wrapped)
return handler(srv, stream)
}
}

View File

@ -17,20 +17,20 @@ type ctxKey struct{}
// GetRoles returns roles stored in the context by the Injector interceptor.
// May be used for additional checks in the API method handler.
func GetRoles(ctx context.Context) role.Set {
roles := rolesFromContext(ctx)
set, ok := getFromContext(ctx)
if roles == nil {
if !ok {
panic("no roles in the context")
}
return roles
return set
}
// rolesFromContext returns roles stored in the context, or nil.
func rolesFromContext(ctx context.Context) role.Set {
roles, _ := ctx.Value(ctxKey{}).(role.Set) //nolint:errcheck
// getFromContext returns roles stored in the context.
func getFromContext(ctx context.Context) (role.Set, bool) {
set, ok := ctx.Value(ctxKey{}).(role.Set)
return roles
return set, ok
}
// ContextWithRoles returns derived context with roles set.

View File

@ -16,10 +16,24 @@ import (
"github.com/talos-systems/talos/pkg/machinery/role"
)
// InjectorMode specifies how roles are extracted.
type InjectorMode int
const (
// Disabled is used when RBAC is disabled in the machine configuration. All roles are assumed.
Disabled InjectorMode = iota
// MetadataOnly is used internally. Checks only metadata.
MetadataOnly
// Enabled is used when RBAC is enabled in the machine configuration. Roles are extracted normally.
Enabled
)
// Injector sets roles to the context.
type Injector struct {
// If true, trust roles in gRPC metadata, do not check certificate.
TrustMetadata bool
// Mode.
Mode InjectorMode
// Logger.
Logger func(format string, v ...interface{})
@ -32,15 +46,25 @@ func (i *Injector) logf(format string, v ...interface{}) {
}
// extractRoles returns roles extracted from the user's certificate (in case of the first apid instance),
// or from gRPC metadata (in case of subsequent apid instances or machined).
// or from gRPC metadata (in case of subsequent apid instances, machined, or user with impersonator role).
func (i *Injector) extractRoles(ctx context.Context) role.Set {
// sanity check
if rolesFromContext(ctx) != nil {
if _, ok := getFromContext(ctx); ok {
panic("roles should not be present in the context at this point")
}
// check certificate first, if needed
if !i.TrustMetadata {
switch i.Mode {
case Disabled:
i.logf("RBAC is disabled, injecting all roles")
return role.All
case MetadataOnly:
roles, _ := getFromMetadata(ctx, i.logf)
return roles
case Enabled:
p, ok := peer.FromContext(ctx)
if !ok {
panic("can't get peer information")
@ -59,17 +83,25 @@ func (i *Injector) extractRoles(ctx context.Context) role.Set {
// TODO validate cert.KeyUsage, cert.ExtKeyUsage, cert.Issuer.Organization, other fields there?
roles, err := role.Parse(strings)
i.logf("parsed peer's orgs %v as %v (err = %v)", strings, roles.Strings(), err)
roles, unknownRoles := role.Parse(strings)
i.logf("parsed peer's certificate orgs %v as %v (unknownRoles = %v)", strings, roles.Strings(), unknownRoles)
// not impersonator (not proxied request), return extracted roles
if _, ok := roles[role.Impersonator]; !ok {
return roles
// trust gRPC metadata from clients with impersonator role if present
// (including requests proxied from other apid instances)
if roles.Includes(role.Impersonator) {
metadataRoles, ok := getFromMetadata(ctx, i.logf)
if ok {
return metadataRoles
}
// that's a real user with impersonator role then
i.logf("no roles in metadadata, returning parsed roles")
}
return roles
}
// trust gRPC metadata from clients with impersonator role (that's proxied request), or if configured
return getFromMetadata(ctx, i.logf)
panic("not reached")
}
// UnaryInterceptor returns grpc UnaryServerInterceptor.

View File

@ -22,18 +22,25 @@ func RolesAsMetadata(roles role.Set) metadata.MD {
}
// getFromMetadata returns roles extracted from from gRPC metadata.
func getFromMetadata(ctx context.Context, logf func(format string, v ...interface{})) role.Set {
func getFromMetadata(ctx context.Context, logf func(format string, v ...interface{})) (role.Set, bool) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
panic("no request metadata")
}
strings := md.Get(mdKey)
roles, err := role.Parse(strings)
if len(strings) == 0 {
if logf != nil {
logf("no roles in metadata")
}
if logf != nil {
logf("parsed metadata %v as %v (err = %v)", strings, roles.Strings(), err)
return role.Zero, false
}
return roles
roles, unknownRoles := role.Parse(strings)
if logf != nil {
logf("parsed metadata %v as %v (unknownRoles = %v)", strings, roles.Strings(), unknownRoles)
}
return roles, true
}

View File

@ -39,7 +39,7 @@ func (l *Local) String() string {
// GetConnection returns a grpc connection to the backend.
func (l *Local) GetConnection(ctx context.Context) (context.Context, *grpc.ClientConn, error) {
md, _ := metadata.FromIncomingContext(ctx)
md = metadata.Join(md, authz.RolesAsMetadata(authz.GetRoles(ctx)))
md = metadata.Join(md, authz.RolesAsMetadata(authz.GetRoles(ctx))) // TODO(rbac): duplicates?
outCtx := metadata.NewOutgoingContext(ctx, md)

View File

@ -234,13 +234,11 @@ var file_cluster_cluster_proto_rawDesc = []byte{
0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68,
0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x63, 0x6c, 0x75,
0x73, 0x74, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b,
0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x30, 0x01, 0x42, 0x59, 0x0a, 0x0f, 0x63, 0x6f,
0x6d, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0a, 0x43,
0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x70, 0x69, 0x50, 0x01, 0x5a, 0x38, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2d, 0x73, 0x79,
0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f,
0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6c,
0x75, 0x73, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x30, 0x01, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2d, 0x73,
0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67,
0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63,
0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -314,14 +314,12 @@ var file_inspect_inspect_proto_rawDesc = []byte{
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2e,
0x2e, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
0x6c, 0x65, 0x72, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64,
0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x59,
0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x61, 0x70,
0x69, 0x42, 0x0a, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x41, 0x70, 0x69, 0x50, 0x01, 0x5a,
0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x61, 0x6c, 0x6f,
0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f,
0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70,
0x69, 0x2f, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3a,
0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x61, 0x6c,
0x6f, 0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73,
0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61,
0x70, 0x69, 0x2f, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (

File diff suppressed because it is too large Load Diff

View File

@ -71,6 +71,8 @@ type MachineServiceClient interface {
SystemStat(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*SystemStatResponse, error)
Upgrade(ctx context.Context, in *UpgradeRequest, opts ...grpc.CallOption) (*UpgradeResponse, error)
Version(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*VersionResponse, error)
// GenerateClientConfiguration generates talosctl client configuration (talosconfig).
GenerateClientConfiguration(ctx context.Context, in *GenerateClientConfigurationRequest, opts ...grpc.CallOption) (*GenerateClientConfigurationResponse, error)
}
type machineServiceClient struct {
@ -682,6 +684,15 @@ func (c *machineServiceClient) Version(ctx context.Context, in *emptypb.Empty, o
return out, nil
}
func (c *machineServiceClient) GenerateClientConfiguration(ctx context.Context, in *GenerateClientConfigurationRequest, opts ...grpc.CallOption) (*GenerateClientConfigurationResponse, error) {
out := new(GenerateClientConfigurationResponse)
err := c.cc.Invoke(ctx, "/machine.MachineService/GenerateClientConfiguration", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// MachineServiceServer is the server API for MachineService service.
// All implementations must embed UnimplementedMachineServiceServer
// for forward compatibility
@ -735,6 +746,8 @@ type MachineServiceServer interface {
SystemStat(context.Context, *emptypb.Empty) (*SystemStatResponse, error)
Upgrade(context.Context, *UpgradeRequest) (*UpgradeResponse, error)
Version(context.Context, *emptypb.Empty) (*VersionResponse, error)
// GenerateClientConfiguration generates talosctl client configuration (talosconfig).
GenerateClientConfiguration(context.Context, *GenerateClientConfigurationRequest) (*GenerateClientConfigurationResponse, error)
mustEmbedUnimplementedMachineServiceServer()
}
@ -904,6 +917,10 @@ func (UnimplementedMachineServiceServer) Upgrade(context.Context, *UpgradeReques
func (UnimplementedMachineServiceServer) Version(context.Context, *emptypb.Empty) (*VersionResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Version not implemented")
}
func (UnimplementedMachineServiceServer) GenerateClientConfiguration(context.Context, *GenerateClientConfigurationRequest) (*GenerateClientConfigurationResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GenerateClientConfiguration not implemented")
}
func (UnimplementedMachineServiceServer) mustEmbedUnimplementedMachineServiceServer() {}
// UnsafeMachineServiceServer may be embedded to opt out of forward compatibility for this service.
@ -1690,6 +1707,24 @@ func _MachineService_Version_Handler(srv interface{}, ctx context.Context, dec f
return interceptor(ctx, in, info, handler)
}
func _MachineService_GenerateClientConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GenerateClientConfigurationRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MachineServiceServer).GenerateClientConfiguration(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/machine.MachineService/GenerateClientConfiguration",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MachineServiceServer).GenerateClientConfiguration(ctx, req.(*GenerateClientConfigurationRequest))
}
return interceptor(ctx, in, info, handler)
}
// MachineService_ServiceDesc is the grpc.ServiceDesc for MachineService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@ -1821,6 +1856,10 @@ var MachineService_ServiceDesc = grpc.ServiceDesc{
MethodName: "Version",
Handler: _MachineService_Version_Handler,
},
{
MethodName: "GenerateClientConfiguration",
Handler: _MachineService_GenerateClientConfiguration_Handler,
},
},
Streams: []grpc.StreamDesc{
{

View File

@ -740,13 +740,11 @@ var file_network_network_proto_rawDesc = []byte{
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x42, 0x59, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f,
0x72, 0x6b, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0a, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x41,
0x70, 0x69, 0x50, 0x01, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74,
0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6e, 0x73, 0x65, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f,
0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e,
0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -802,13 +802,11 @@ var file_resource_resource_proto_rawDesc = []byte{
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
0x57, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x42,
0x5c, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
0x61, 0x70, 0x69, 0x42, 0x0b, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x70, 0x69,
0x50, 0x01, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74,
0x61, 0x6c, 0x6f, 0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74, 0x61, 0x6c,
0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79,
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x61,
0x6c, 0x6f, 0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f,
0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f,
0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -142,14 +142,12 @@ var file_security_security_proto_rawDesc = []byte{
0x72, 0x69, 0x74, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x65, 0x63,
0x75, 0x72, 0x69, 0x74, 0x79, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x5c, 0x0a, 0x10,
0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x70, 0x69,
0x42, 0x0b, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x41, 0x70, 0x69, 0x50, 0x01, 0x5a,
0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x61, 0x6c, 0x6f,
0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f,
0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70,
0x69, 0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3b, 0x5a, 0x39,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73,
0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70,
0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69,
0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (

View File

@ -344,13 +344,11 @@ var file_storage_storage_proto_rawDesc = []byte{
0x73, 0x6b, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x73, 0x74,
0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x44, 0x69, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x42, 0x59, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61,
0x67, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0a, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x41,
0x70, 0x69, 0x50, 0x01, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74,
0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6e, 0x73, 0x65, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f,
0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e,
0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -227,12 +227,11 @@ var file_time_time_proto_rawDesc = []byte{
0x65, 0x12, 0x32, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x11,
0x2e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x12, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x50, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x69, 0x6d,
0x65, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x07, 0x54, 0x69, 0x6d, 0x65, 0x41, 0x70, 0x69, 0x50, 0x01,
0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x61, 0x6c,
0x6f, 0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73,
0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61,
0x70, 0x69, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68,
0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -35,7 +35,7 @@ import (
resourceapi "github.com/talos-systems/talos/pkg/machinery/api/resource"
storageapi "github.com/talos-systems/talos/pkg/machinery/api/storage"
timeapi "github.com/talos-systems/talos/pkg/machinery/api/time"
"github.com/talos-systems/talos/pkg/machinery/client/config"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
"github.com/talos-systems/talos/pkg/machinery/constants"
)
@ -103,7 +103,7 @@ func (c *Client) resolveConfigContext() error {
}
// GetConfigContext returns resolved config context.
func (c *Client) GetConfigContext() *config.Context {
func (c *Client) GetConfigContext() *clientconfig.Context {
if err := c.resolveConfigContext(); err != nil {
return nil
}
@ -223,7 +223,7 @@ func (c *Client) getConn(ctx context.Context, opts ...grpc.DialOption) (*grpc.Cl
}
// CredentialsFromConfigContext constructs the client Credentials from the given configuration Context.
func CredentialsFromConfigContext(context *config.Context) (*Credentials, error) {
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)
@ -253,8 +253,8 @@ func CredentialsFromConfigContext(context *config.Context) (*Credentials, error)
// NewClientContextAndCredentialsFromConfig initializes Credentials from config file.
//
// Deprecated: use Option-based methods for client creation.
func NewClientContextAndCredentialsFromConfig(p, ctx string) (context *config.Context, creds *Credentials, err error) {
c, err := config.Open(p)
func NewClientContextAndCredentialsFromConfig(p, ctx string) (context *clientconfig.Context, creds *Credentials, err error) {
c, err := clientconfig.Open(p)
if err != nil {
return
}
@ -267,7 +267,7 @@ func NewClientContextAndCredentialsFromConfig(p, ctx string) (context *config.Co
// NewClientContextAndCredentialsFromParsedConfig initializes Credentials from parsed configuration.
//
// Deprecated: use Option-based methods for client creation.
func NewClientContextAndCredentialsFromParsedConfig(c *config.Config, ctx string) (context *config.Context, creds *Credentials, err error) {
func NewClientContextAndCredentialsFromParsedConfig(c *clientconfig.Config, ctx string) (context *clientconfig.Context, creds *Credentials, err error) {
if ctx != "" {
c.Context = ctx
}
@ -940,6 +940,17 @@ func (c *Client) EtcdRecover(ctx context.Context, snapshot io.Reader, callOption
return cli.CloseAndRecv()
}
// GenerateClientConfiguration implements proto.MachineServiceClient interface.
func (c *Client) GenerateClientConfiguration(ctx context.Context, req *machineapi.GenerateClientConfigurationRequest, callOptions ...grpc.CallOption) (resp *machineapi.GenerateClientConfigurationResponse, err error) { //nolint:lll
resp, err = c.MachineClient.GenerateClientConfiguration(ctx, req, callOptions...)
var filtered interface{}
filtered, err = FilterMessages(resp, err)
resp, _ = filtered.(*machineapi.GenerateClientConfigurationResponse) //nolint:errcheck
return
}
// MachineStream is a common interface for streams returned by streaming APIs.
type MachineStream interface {
Recv() (*common.Data, error)

View File

@ -6,21 +6,38 @@ package config
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/talos-systems/crypto/x509"
yaml "gopkg.in/yaml.v3"
)
// Config represents the configuration file.
// Config represents the client configuration file (talosconfig).
type Config struct {
Context string `yaml:"context"`
Contexts map[string]*Context `yaml:"contexts"`
}
// NewConfig returns the client configuration file with a single context.
func NewConfig(contextName string, endpoints []string, caCrt []byte, client *x509.PEMEncodedCertificateAndKey) *Config {
return &Config{
Context: contextName,
Contexts: map[string]*Context{
contextName: {
Endpoints: endpoints,
CA: base64.StdEncoding.EncodeToString(caCrt),
Crt: base64.StdEncoding.EncodeToString(client.Crt),
Key: base64.StdEncoding.EncodeToString(client.Key),
},
},
}
}
func (c *Config) upgrade() {
for _, ctx := range c.Contexts {
ctx.upgrade()

View File

@ -9,74 +9,74 @@ import (
"github.com/stretchr/testify/assert"
"github.com/talos-systems/talos/pkg/machinery/client/config"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
)
func TestConfigMerge(t *testing.T) {
context1 := &config.Context{}
context2 := &config.Context{}
context1 := &clientconfig.Context{}
context2 := &clientconfig.Context{}
for _, tt := range []struct {
name string
config *config.Config
configToMerge *config.Config
config *clientconfig.Config
configToMerge *clientconfig.Config
expectedContext string
expectedContexts map[string]*config.Context
expectedContexts map[string]*clientconfig.Context
}{
{
name: "IntoEmpty",
config: &config.Config{},
configToMerge: &config.Config{
config: &clientconfig.Config{},
configToMerge: &clientconfig.Config{
Context: "foo",
Contexts: map[string]*config.Context{
Contexts: map[string]*clientconfig.Context{
"foo": context1,
},
},
expectedContext: "foo",
expectedContexts: map[string]*config.Context{
expectedContexts: map[string]*clientconfig.Context{
"foo": context1,
},
},
{
name: "NoConflict",
config: &config.Config{
config: &clientconfig.Config{
Context: "bar",
Contexts: map[string]*config.Context{
Contexts: map[string]*clientconfig.Context{
"bar": context2,
},
},
configToMerge: &config.Config{
configToMerge: &clientconfig.Config{
Context: "",
Contexts: map[string]*config.Context{
Contexts: map[string]*clientconfig.Context{
"foo": context1,
},
},
expectedContext: "bar",
expectedContexts: map[string]*config.Context{
expectedContexts: map[string]*clientconfig.Context{
"foo": context1,
"bar": context2,
},
},
{
name: "WithRename",
config: &config.Config{
config: &clientconfig.Config{
Context: "bar",
Contexts: map[string]*config.Context{
Contexts: map[string]*clientconfig.Context{
"bar": context2,
},
},
configToMerge: &config.Config{
configToMerge: &clientconfig.Config{
Context: "bar",
Contexts: map[string]*config.Context{
Contexts: map[string]*clientconfig.Context{
"bar": context1,
},
},
expectedContext: "bar-1",
expectedContexts: map[string]*config.Context{
expectedContexts: map[string]*clientconfig.Context{
"bar-1": context1,
"bar": context2,
},

View File

@ -10,14 +10,14 @@ import (
"google.golang.org/grpc"
"github.com/talos-systems/talos/pkg/machinery/client/config"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
)
// Options contains the set of client configuration options.
type Options struct {
endpointsOverride []string
config *config.Config
configContext *config.Context
config *clientconfig.Config
configContext *clientconfig.Context
tlsConfig *tls.Config
grpcDialOptions []grpc.DialOption
@ -32,7 +32,7 @@ type OptionFunc func(*Options) error
// WithConfig configures the Client with the configuration provided.
// Additionally use WithContextName to override the default context in the Config.
func WithConfig(cfg *config.Config) OptionFunc {
func WithConfig(cfg *clientconfig.Config) OptionFunc {
return func(o *Options) error {
o.config = cfg
@ -52,7 +52,7 @@ func WithContextName(name string) OptionFunc {
}
// WithConfigContext configures the Client with the configuration context provided.
func WithConfigContext(cfg *config.Context) OptionFunc {
func WithConfigContext(cfg *clientconfig.Context) OptionFunc {
return func(o *Options) error {
o.configContext = cfg
@ -92,7 +92,7 @@ func WithEndpoints(endpoints ...string) OptionFunc {
// Additionally use WithContextName to select a context other than the default.
func WithDefaultConfig() OptionFunc {
return func(o *Options) (err error) {
defaultConfigPath, err := config.GetDefaultPath()
defaultConfigPath, err := clientconfig.GetDefaultPath()
if err != nil {
return fmt.Errorf("no client configuration provided and no default path found: %w", err)
}
@ -105,7 +105,7 @@ func WithDefaultConfig() OptionFunc {
// Additionally use WithContextName to select a context other than the default.
func WithConfigFromFile(fn string) OptionFunc {
return func(o *Options) (err error) {
cfg, err := config.Open(fn)
cfg, err := clientconfig.Open(fn)
if err != nil {
return fmt.Errorf("failed to read config from %q: %w", fn, err)
}

View File

@ -29,7 +29,7 @@ func (ne *NodeError) Unwrap() error {
return ne.Err
}
// FilterMessages removes error Messagess from resp and builds multierror.
// FilterMessages removes error Messages from resp and builds multierror.
//
//nolint:gocyclo,cyclop
func FilterMessages(resp interface{}, err error) (interface{}, error) {
@ -152,7 +152,7 @@ func FilterMessages(resp interface{}, err error) (interface{}, error) {
messagesField.SetLen(messagesField.Len() - 1)
}
// if all the Messagess were error Messagess...
// if all the Messages were error Messages...
if multiErr != nil && messagesField.Len() == 0 {
resp = nil
}

View File

@ -5,12 +5,14 @@
// Package config provides methods to generate and consume Talos configuration.
package config
import "github.com/talos-systems/talos/pkg/machinery/client/config"
import (
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
)
// ProviderBundle defines the configuration bundle interface.
type ProviderBundle interface {
Init() Provider
ControlPlane() Provider
Join() Provider
TalosConfig() *config.Config
TalosConfig() *clientconfig.Config
}

View File

@ -13,7 +13,7 @@ import (
yaml "gopkg.in/yaml.v3"
"github.com/talos-systems/talos/pkg/machinery/client/config"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/generate"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine"
@ -72,7 +72,7 @@ func NewConfigBundle(opts ...Option) (*v1alpha1.ConfigBundle, error) {
defer talosConfig.Close() //nolint:errcheck
if bundle.TalosCfg, err = config.ReadFrom(talosConfig); err != nil {
if bundle.TalosCfg, err = clientconfig.ReadFrom(talosConfig); err != nil {
return bundle, err
}

View File

@ -384,13 +384,10 @@ func NewTalosCA(currentTime time.Time) (ca *x509.CertificateAuthority, err error
}
// NewAdminCertificateAndKey generates the admin Talos certificate and key.
func NewAdminCertificateAndKey(currentTime time.Time, ca *x509.PEMEncodedCertificateAndKey, loopback string, role role.Role) (p *x509.PEMEncodedCertificateAndKey, err error) {
ips := []net.IP{net.ParseIP(loopback)}
func NewAdminCertificateAndKey(currentTime time.Time, ca *x509.PEMEncodedCertificateAndKey, roles role.Set, ttl time.Duration) (p *x509.PEMEncodedCertificateAndKey, err error) {
opts := []x509.Option{
x509.Organization(string(role)),
x509.IPAddresses(ips),
x509.NotAfter(currentTime.Add(87600 * time.Hour)),
x509.Organization(roles.Strings()...),
x509.NotAfter(currentTime.Add(ttl)),
x509.NotBefore(currentTime),
}
@ -418,14 +415,12 @@ func NewInput(clustername, endpoint, kubernetesVersion string, secrets *SecretsB
}
}
var loopback, podNet, serviceNet string
var podNet, serviceNet string
if tnet.IsIPv6(net.ParseIP(endpoint)) {
loopback = "::1"
podNet = constants.DefaultIPv6PodNet
serviceNet = constants.DefaultIPv6ServiceNet
} else {
loopback = "127.0.0.1"
podNet = constants.DefaultIPv4PodNet
serviceNet = constants.DefaultIPv4ServiceNet
}
@ -433,8 +428,8 @@ func NewInput(clustername, endpoint, kubernetesVersion string, secrets *SecretsB
secrets.Certs.Admin, err = NewAdminCertificateAndKey(
secrets.Clock.Now(),
secrets.Certs.OS,
loopback,
role.Admin,
options.Roles,
87600*time.Hour,
)
if err != nil {

View File

@ -7,6 +7,7 @@ package generate
import (
"github.com/talos-systems/talos/pkg/machinery/config"
v1alpha1 "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
"github.com/talos-systems/talos/pkg/machinery/role"
)
// GenOption controls generate options specific to input generation.
@ -193,6 +194,15 @@ func WithSystemDiskEncryption(cfg *v1alpha1.SystemDiskEncryptionConfig) GenOptio
}
}
// WithRoles specifies user roles.
func WithRoles(roles role.Set) GenOption {
return func(o *GenOptions) error {
o.Roles = roles
return nil
}
}
// GenOptions describes generate parameters.
type GenOptions struct {
EndpointList []string
@ -211,11 +221,13 @@ type GenOptions struct {
MachineDisks []*v1alpha1.MachineDisk
VersionContract *config.VersionContract
SystemDiskEncryptionConfig *v1alpha1.SystemDiskEncryptionConfig
Roles role.Set
}
// DefaultGenOptions returns default options.
func DefaultGenOptions() GenOptions {
return GenOptions{
Persist: true,
Roles: role.MakeSet(role.Admin),
}
}

View File

@ -5,13 +5,11 @@
package generate
import (
"encoding/base64"
"github.com/talos-systems/talos/pkg/machinery/client/config"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
)
// Talosconfig returns the talos admin Talos config.
func Talosconfig(in *Input, opts ...GenOption) (*config.Config, error) {
func Talosconfig(in *Input, opts ...GenOption) (*clientconfig.Config, error) {
options := DefaultGenOptions()
for _, opt := range opts {
@ -20,15 +18,5 @@ func Talosconfig(in *Input, opts ...GenOption) (*config.Config, error) {
}
}
return &config.Config{
Context: in.ClusterName,
Contexts: map[string]*config.Context{
in.ClusterName: {
Endpoints: options.EndpointList,
CA: base64.StdEncoding.EncodeToString(in.Certs.OS.Crt),
Crt: base64.StdEncoding.EncodeToString(in.Certs.Admin.Crt),
Key: base64.StdEncoding.EncodeToString(in.Certs.Admin.Key),
},
},
}, nil
return clientconfig.NewConfig(in.ClusterName, options.EndpointList, in.Certs.OS.Crt, in.Certs.Admin), nil
}

View File

@ -24,7 +24,7 @@ require (
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d
github.com/stretchr/objx v0.3.0 // indirect
github.com/stretchr/testify v1.7.0
github.com/talos-systems/crypto v0.2.1-0.20210601174604-cd18ef62eb9f
github.com/talos-systems/crypto v0.3.1-0.20210615131117-6bc5bb50c527
github.com/talos-systems/go-blockdevice v0.2.1-0.20210526155905-30c2bc3cb62a
github.com/talos-systems/net v0.2.1-0.20210212213224-05190541b0fa
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea

View File

@ -144,8 +144,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/talos-systems/crypto v0.2.1-0.20210601174604-cd18ef62eb9f h1:Xk3zeUZPhvEl9Vs4PlYBohin3QZmizA/YR4URKEyULY=
github.com/talos-systems/crypto v0.2.1-0.20210601174604-cd18ef62eb9f/go.mod h1:xaNCB2/Bxaj+qrkdeodhRv5eKQVvKOGBBMj58MrIPY8=
github.com/talos-systems/crypto v0.3.1-0.20210615131117-6bc5bb50c527 h1:Ut3jI/0FPSyH0QpycKFKAueWKjzQ00OFmkeFG+0uO1A=
github.com/talos-systems/crypto v0.3.1-0.20210615131117-6bc5bb50c527/go.mod h1:xaNCB2/Bxaj+qrkdeodhRv5eKQVvKOGBBMj58MrIPY8=
github.com/talos-systems/go-blockdevice v0.2.1-0.20210526155905-30c2bc3cb62a h1:NLuIVKi5tBnRMgxk185AVGmMUzlRcggb2Abrw9uUq3E=
github.com/talos-systems/go-blockdevice v0.2.1-0.20210526155905-30c2bc3cb62a/go.mod h1:qnn/zDc09I1DA2BUDDCOSA2D0P8pIDjN8pGiRoRaQig=
github.com/talos-systems/go-cmd v0.0.0-20210216164758-68eb0067e0f0/go.mod h1:kf+rZzTEmlDiYQ6ulslvRONnKLQH8x83TowltGMhO+k=

View File

@ -5,11 +5,8 @@
package role
import (
"fmt"
"sort"
"strings"
"github.com/hashicorp/go-multierror"
)
// Role represents Talos user role.
@ -18,28 +15,41 @@ import (
type Role string
const (
// Prefix for all built-in roles.
Prefix = string("os:")
// Admin defines Talos role for admins.
Admin = Role("os:admin")
Admin = Role(Prefix + "admin")
// Reader defines Talos role for readers who can access read-only APIs that do not expose secrets.
Reader = Role("os:reader")
Reader = Role(Prefix + "reader")
// Impersonator defines internal Talos role for impersonating another user (and their role).
Impersonator = Role("os:impersonator")
// Impersonator defines Talos role for impersonating another user (and their role).
// Used internally, but may also be granted to the user.
Impersonator = Role(Prefix + "impersonator")
)
// Set represents a set of roles.
type Set map[Role]struct{}
type Set struct {
roles map[Role]struct{}
}
// all roles, including internal ones.
var all = MakeSet(Admin, Reader, Impersonator)
var (
// All roles that can be granted to users.
All = MakeSet(Admin, Reader, Impersonator)
// Zero is an empty set of roles.
Zero = MakeSet()
)
// MakeSet makes a set of roles from constants.
// Use Parse in other cases.
func MakeSet(roles ...Role) Set {
res := make(Set, len(roles))
res := Set{
roles: make(map[Role]struct{}, len(roles)),
}
for _, r := range roles {
res[r] = struct{}{}
res.roles[r] = struct{}{}
}
return res
@ -47,11 +57,11 @@ func MakeSet(roles ...Role) Set {
// Parse parses a set of roles.
// The returned set is always non-nil and contains all roles, including unknown (for compatibility with future versions).
// The returned error contains roles unknown to the current version.
func Parse(str []string) (Set, error) {
res := make(Set)
// The returned slice contains roles unknown to the current version.
func Parse(str []string) (Set, []string) {
res := MakeSet()
var err *multierror.Error
var unknownRoles []string
for _, r := range str {
r = strings.TrimSpace(r)
@ -62,21 +72,21 @@ func Parse(str []string) (Set, error) {
}
role := Role(r)
if _, ok := all[role]; !ok {
err = multierror.Append(err, fmt.Errorf("unexpected role %q", r))
if _, ok := All.roles[role]; !ok {
unknownRoles = append(unknownRoles, r)
}
res[role] = struct{}{}
res.roles[role] = struct{}{}
}
return res, err.ErrorOrNil()
return res, unknownRoles
}
// Strings returns a set as a slice of strings.
func (s Set) Strings() []string {
res := make([]string, 0, len(s))
res := make([]string, 0, len(s.roles))
for r := range s {
for r := range s.roles {
res = append(res, string(r))
}
@ -86,12 +96,21 @@ func (s Set) Strings() []string {
}
// IncludesAny returns true if there is a non-empty intersection between sets.
//
// Returns false if any set is empty.
func (s Set) IncludesAny(other Set) bool {
for r := range other {
if _, ok := s[r]; ok {
for r := range other.roles {
if _, ok := s.roles[r]; ok {
return true
}
}
return false
}
// Includes returns true if given role is present in the set.
func (s Set) Includes(role Role) bool {
_, ok := s.roles[role]
return ok
}

View File

@ -12,18 +12,23 @@ import (
"github.com/talos-systems/talos/pkg/machinery/role"
)
func TestRole(t *testing.T) {
func TestSet(t *testing.T) {
t.Parallel()
set, err := role.Parse([]string{"os:admin", "os:reader", "os:future", "os:impersonator", "", " "})
assert.EqualError(t, err, "1 error occurred:\n\t* unexpected role \"os:future\"\n\n")
assert.Equal(t, role.MakeSet(role.Admin, role.Reader, role.Role("os:future"), role.Impersonator), set)
roles, unknownRoles := role.Parse([]string{"os:admin", "os:reader", "os:future", "os:impersonator", "", " "})
assert.Equal(t, []string{"os:future"}, unknownRoles)
assert.Equal(t, role.MakeSet(role.Admin, role.Reader, role.Role("os:future"), role.Impersonator), roles)
assert.Equal(t, []string{"os:admin", "os:future", "os:impersonator", "os:reader"}, set.Strings())
assert.Equal(t, []string{}, role.Set.Strings(nil))
assert.Equal(t, []string{"os:admin", "os:future", "os:impersonator", "os:reader"}, roles.Strings())
assert.Equal(t, []string{}, role.MakeSet().Strings())
_, ok := set[role.Admin]
assert.True(t, ok)
assert.True(t, set.IncludesAny(role.MakeSet(role.Admin)))
assert.False(t, set.IncludesAny(nil))
assert.True(t, roles.Includes(role.Admin))
assert.False(t, roles.Includes(role.Role("wrong")))
assert.True(t, roles.IncludesAny(role.MakeSet(role.Admin)))
assert.False(t, roles.IncludesAny(role.MakeSet(role.Role("wrong"))))
assert.False(t, roles.IncludesAny(role.MakeSet()))
assert.False(t, role.MakeSet().IncludesAny(roles))
assert.False(t, role.MakeSet().IncludesAny(role.MakeSet()))
}

View File

@ -10,7 +10,7 @@ import (
"runtime"
"github.com/talos-systems/talos/pkg/machinery/client"
"github.com/talos-systems/talos/pkg/machinery/client/config"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
)
// Option controls Provisioner.
@ -35,7 +35,7 @@ func WithEndpoint(endpoint string) Option {
}
// WithTalosConfig specifies talosconfig to use when acessing Talos cluster.
func WithTalosConfig(talosConfig *config.Config) Option {
func WithTalosConfig(talosConfig *clientconfig.Config) Option {
return func(o *Options) error {
o.TalosConfig = talosConfig
@ -100,7 +100,7 @@ func WithDockerPortsHostIP(hostIP string) Option {
// Options describes Provisioner parameters.
type Options struct {
LogWriter io.Writer
TalosConfig *config.Config
TalosConfig *clientconfig.Config
TalosClient *client.Client
ForceEndpoint string
TargetArch string

View File

@ -8,15 +8,16 @@
# Protoc directives.
protoc:
# The Protobuf version to use from https://github.com/protocolbuffers/protobuf/releases.
# By default use 3.8.0.
# By default use 3.11.0.
# You probably want to set this to make your builds completely reproducible.
version: 3.15.3
version: 3.15.6
# Additional paths to include with -I to protoc.
# By default, the directory of the config file is included,
# or the current directory if there is no config file.
includes:
- vendor/
# If not set, compile will fail if there are unused imports.
# Setting this will ignore unused imports.
#allow_unused_imports: true
@ -44,28 +45,103 @@ lint:
# lint rules in lint.rules.add.
# Run prototool lint --list-all-lint-groups to see all available lint groups.
# Run prototool lint --list-lint-group GROUP to list the linters in the given lint group.
group: google
group: empty
# Linter files to ignore.
# These can either be file or directory names.
# If there is a directory name, that directory and all sub-directories will be ignored.
# ignores:
# - id: RPC_NAMES_CAMEL_CASE
# files:
# - path/to/foo.proto
# - path/to/bar.proto
# - id: SYNTAX_PROTO3
# files:
# - path/to/dir
ignores:
- id: FILE_OPTIONS_GO_PACKAGE_NOT_LONG_FORM
files:
- vendor/google/rpc/status.proto
- id: NAMES_NO_COMMON
files:
- common/common.proto
# Linter rules.
# Run prototool lint --list-all-linters to see all available linters.
# Run prototool lint --list-linters to see the currently configured linters.
# rules:
# Linter rules.
# Run prototool lint --list-all-linters to see all available linters.
# Run prototool lint --list-linters to see the currently configured linters.
rules:
# The specific linters to add.
# add:
# - ENUM_NAMES_CAMEL_CASE
# - ENUM_NAMES_CAPITALIZED
# The specific linters to add.
# TODO Enable more: https://github.com/talos-systems/talos/issues/2722.
add:
# All rules except language-specific (C#, Java, Obj-C, PHP, Ruby, but not Go).
- COMMENTS_NO_C_STYLE # Verifies that there are no /* c-style */ comments.
# - COMMENTS_NO_INLINE # Verifies that there are no inline comments.
# - ENUMS_HAVE_COMMENTS # Verifies that all enums have a comment of the form "// EnumName ...".
# - ENUMS_HAVE_SENTENCE_COMMENTS # Verifies that all enums have a comment that contains at least one complete sentence.
# - ENUMS_NO_ALLOW_ALIAS # Verifies that no enums use the option "allow_alias".
# - ENUM_FIELDS_HAVE_COMMENTS # Verifies that all enum fields have a comment of the form "// FIELD_NAME ...".
# - ENUM_FIELDS_HAVE_SENTENCE_COMMENTS # Verifies that all enum fields have a comment that contains at least one complete sentence.
- ENUM_FIELD_NAMES_UPPERCASE # Verifies that all enum field names are UPPERCASE.
- ENUM_FIELD_NAMES_UPPER_SNAKE_CASE # Verifies that all enum field names are UPPER_SNAKE_CASE.
# - ENUM_FIELD_PREFIXES # Verifies that all enum fields are prefixed with [NESTED_MESSAGE_NAME_]ENUM_NAME_.
# - ENUM_FIELD_PREFIXES_EXCEPT_MESSAGE # Verifies that all enum fields are prefixed with ENUM_NAME_.
- ENUM_NAMES_CAMEL_CASE # Verifies that all enum names are CamelCase.
- ENUM_NAMES_CAPITALIZED # Verifies that all enum names are Capitalized.
# - ENUM_ZERO_VALUES_INVALID # Verifies that all enum zero value names are [NESTED_MESSAGE_NAME_]ENUM_NAME_INVALID.
# - ENUM_ZERO_VALUES_INVALID_EXCEPT_MESSAGE # Verifies that all enum zero value names are ENUM_NAME_INVALID.
- FIELDS_NOT_RESERVED # Verifies that no message or enum has a reserved field.
- FILE_HEADER # Verifies that the file header matches the expected file header if the file_header option is set in the configuration file.
- FILE_NAMES_LOWER_SNAKE_CASE # Verifies that the file name is lower_snake_case.proto.
# - FILE_OPTIONS_EQUAL_GO_PACKAGE_PB_SUFFIX # Verifies that the file option "go_package" is equal to $(basename PACKAGE)pb.
# - FILE_OPTIONS_EQUAL_GO_PACKAGE_V2_SUFFIX # Verifies that the file option "go_package" is equal to the last two values of the package separated by "."s, or just the package name if there are no "."s.
- FILE_OPTIONS_GO_PACKAGE_NOT_LONG_FORM # Verifies that the file option "go_package" is not of the form "go/import/path;package".
- FILE_OPTIONS_GO_PACKAGE_SAME_IN_DIR # Verifies that the file option "go_package" of all files in a directory are the same.
- FILE_OPTIONS_REQUIRE_GO_PACKAGE # Verifies that the file option "go_package" is set.
- GOGO_NOT_IMPORTED # Verifies that the "gogo.proto" file from gogo/protobuf is not imported.
- IMPORTS_NOT_PUBLIC # Verifies that there are no public imports.
- IMPORTS_NOT_WEAK # Verifies that there are no weak imports.
# - MESSAGES_HAVE_COMMENTS # Verifies that all non-extended messages have a comment of the form "// MessageName ...".
# - MESSAGES_HAVE_COMMENTS_EXCEPT_REQUEST_RESPONSE_TYPES # Verifies that all non-extended messages except for request and response types have a comment of the form "// MessageName ...".
# - MESSAGES_HAVE_SENTENCE_COMMENTS_EXCEPT_REQUEST_RESPONSE_TYPES # Verifies that all non-extended messages except for request and response types have a comment that contains at least one complete sentence.
- MESSAGES_NOT_EMPTY_EXCEPT_REQUEST_RESPONSE_TYPES # Verifies that all messages except for request and response types are not empty.
- MESSAGE_FIELDS_DURATION # Verifies that all non-map fields that contain "duration" in their name are google.protobuf.Durations.
# - MESSAGE_FIELDS_HAVE_COMMENTS # Verifies that all message fields have a comment of the form "// field_name ...".
# - MESSAGE_FIELDS_HAVE_SENTENCE_COMMENTS # Verifies that all message fields have a comment that contains at least one complete sentence.
- MESSAGE_FIELDS_NOT_FLOATS # Verifies that all message fields are not floats.
- MESSAGE_FIELDS_NO_JSON_NAME # Verifies that no message field has the "json_name" option set.
# - MESSAGE_FIELDS_TIME # Verifies that all non-map fields that contain "time" in their name are google.protobuf.Timestamps.
- MESSAGE_FIELD_NAMES_FILENAME # Verifies that all message field names do not contain "file_name" as "filename" should be used instead.
- MESSAGE_FIELD_NAMES_FILEPATH # Verifies that all message field names do not contain "file_path" as "filepath" should be used instead.
- MESSAGE_FIELD_NAMES_LOWERCASE # Verifies that all message field names are lowercase.
- MESSAGE_FIELD_NAMES_LOWER_SNAKE_CASE # Verifies that all message field names are lower_snake_case.
- MESSAGE_FIELD_NAMES_NO_DESCRIPTOR # Verifies that all message field names are not "descriptor", which results in a collision in Java-generated code.
- MESSAGE_NAMES_CAMEL_CASE # Verifies that all non-extended message names are CamelCase.
- MESSAGE_NAMES_CAPITALIZED # Verifies that all non-extended message names are Capitalized.
- NAMES_NO_COMMON # Verifies that no type name contains the word "common".
# - NAMES_NO_DATA # Verifies that no type name contains the word "data".
# - NAMES_NO_UUID # Verifies that no type name contains the word "uuid".
- ONEOF_NAMES_LOWER_SNAKE_CASE # Verifies that all oneof names are lower_snake_case.
- PACKAGES_SAME_IN_DIR # Verifies that the packages of all files in a directory are the same.
- PACKAGE_IS_DECLARED # Verifies that there is a package declaration.
- PACKAGE_LOWER_CASE # Verifies that the package name only contains characters in the range a-z0-9 and periods.
- PACKAGE_LOWER_SNAKE_CASE # Verifies that the package is lower_snake.case.
# - PACKAGE_MAJOR_BETA_VERSIONED # Verifies that the package is of the form "package.vMAJORVERSION" or "package.vMAJORVERSIONbetaBETAVERSION" with versions >=1.
- PACKAGE_NO_KEYWORDS # Verifies that no packages contain one of the keywords "internal,public,private,protected,std" as part of the name when split on '.'.
# - REQUEST_RESPONSE_NAMES_MATCH_RPC # Verifies that all request names are RpcNameRequest and all response names are RpcNameResponse.
- REQUEST_RESPONSE_TYPES_AFTER_SERVICE # Verifies that request and response types are defined after any services and the response type is defined after the request type.
# - REQUEST_RESPONSE_TYPES_IN_SAME_FILE # Verifies that all request and response types are in the same file as their corresponding service and are not nested messages.
# - REQUEST_RESPONSE_TYPES_ONLY_IN_FILE # Verifies that only request and response types are the only types in the same file as their corresponding service.
# - REQUEST_RESPONSE_TYPES_UNIQUE # Verifies that all request and response types are unique to each RPC.
# - RPCS_HAVE_COMMENTS # Verifies that all rpcs have a comment of the form "// RPCName ...".
# - RPCS_HAVE_SENTENCE_COMMENTS # Verifies that all rpcs have a comment that contains at least one complete sentence.
# - RPCS_NO_STREAMING # Verifies that all rpcs are unary.
- RPC_NAMES_CAMEL_CASE # Verifies that all RPC names are CamelCase.
- RPC_NAMES_CAPITALIZED # Verifies that all RPC names are Capitalized.
- RPC_OPTIONS_NO_GOOGLE_API_HTTP # Verifies that the RPC option "google.api.http" is not used.
# - SERVICES_HAVE_COMMENTS # Verifies that all services have a comment of the form "// ServiceName ...".
- SERVICES_HAVE_SENTENCE_COMMENTS # Verifies that all services have a comment that contains at least one complete sentence.
# - SERVICE_NAMES_API_SUFFIX # Verifies that all service names end with "API".
- SERVICE_NAMES_CAMEL_CASE # Verifies that all service names are CamelCase.
- SERVICE_NAMES_CAPITALIZED # Verifies that all service names are Capitalized.
# - SERVICE_NAMES_MATCH_FILE_NAME # Verifies that there is one service per file and the file name is service_name_lower_snake_case.proto.
- SERVICE_NAMES_NO_PLURALS # Verifies that all CamelCase service names do not contain plural components.
- SYNTAX_PROTO3 # Verifies that the syntax is proto3.
- WKT_DIRECTLY_IMPORTED # Verifies that the Well-Known Types are directly imported using "google/protobuf/" as the base of the import.
# - WKT_DURATION_SUFFIX # Verifies that all google.protobuf.Duration field names are "duration" or end in "_duration".
# - WKT_TIMESTAMP_SUFFIX # Verifies that all google.protobuf.Timestamp field names are "time" or end in "_time".
# The specific linters to remove.
# remove:

View File

@ -83,6 +83,9 @@ description: Talos gRPC API reference.
- [Event](#machine.Event)
- [EventsRequest](#machine.EventsRequest)
- [FileInfo](#machine.FileInfo)
- [GenerateClientConfiguration](#machine.GenerateClientConfiguration)
- [GenerateClientConfigurationRequest](#machine.GenerateClientConfigurationRequest)
- [GenerateClientConfigurationResponse](#machine.GenerateClientConfigurationResponse)
- [GenerateConfiguration](#machine.GenerateConfiguration)
- [GenerateConfigurationRequest](#machine.GenerateConfigurationRequest)
- [GenerateConfigurationResponse](#machine.GenerateConfigurationResponse)
@ -109,7 +112,6 @@ description: Talos gRPC API reference.
- [PlatformInfo](#machine.PlatformInfo)
- [Process](#machine.Process)
- [ProcessInfo](#machine.ProcessInfo)
- [ProcessesRequest](#machine.ProcessesRequest)
- [ProcessesResponse](#machine.ProcessesResponse)
- [ReadRequest](#machine.ReadRequest)
- [Reboot](#machine.Reboot)
@ -487,7 +489,7 @@ Common metadata message nested in all reply message types
<a name="health.Health"></a>
### Health
The health service definition.
| Method Name | Request Type | Response Type | Description |
| ----------- | ------------ | ------------- | ------------|
@ -1364,6 +1366,56 @@ TODO: unix timestamp or include proto's Date type |
<a name="machine.GenerateClientConfiguration"></a>
### GenerateClientConfiguration
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| metadata | [common.Metadata](#common.Metadata) | | |
| ca | [bytes](#bytes) | | PEM-encoded CA certificate. |
| crt | [bytes](#bytes) | | PEM-encoded generated client certificate. |
| key | [bytes](#bytes) | | PEM-encoded generated client key. |
| talosconfig | [bytes](#bytes) | | Client configuration (talosconfig) file content. |
<a name="machine.GenerateClientConfigurationRequest"></a>
### GenerateClientConfigurationRequest
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| roles | [string](#string) | repeated | Roles in the generated client certificate. |
| crt_ttl | [google.protobuf.Duration](#google.protobuf.Duration) | | Client certificate TTL. |
<a name="machine.GenerateClientConfigurationResponse"></a>
### GenerateClientConfigurationResponse
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| messages | [GenerateClientConfiguration](#machine.GenerateClientConfiguration) | repeated | |
<a name="machine.GenerateConfiguration"></a>
### GenerateConfiguration
@ -1865,20 +1917,10 @@ The messages message containing the requested df stats.
<a name="machine.ProcessesRequest"></a>
### ProcessesRequest
rpc processes
<a name="machine.ProcessesResponse"></a>
### ProcessesResponse
rpc processes
| Field | Type | Label | Description |
@ -2958,6 +3000,7 @@ This method is available only on control plane nodes (which run etcd). |
| SystemStat | [.google.protobuf.Empty](#google.protobuf.Empty) | [SystemStatResponse](#machine.SystemStatResponse) | |
| Upgrade | [UpgradeRequest](#machine.UpgradeRequest) | [UpgradeResponse](#machine.UpgradeResponse) | |
| Version | [.google.protobuf.Empty](#google.protobuf.Empty) | [VersionResponse](#machine.VersionResponse) | |
| GenerateClientConfiguration | [GenerateClientConfigurationRequest](#machine.GenerateClientConfigurationRequest) | [GenerateClientConfigurationResponse](#machine.GenerateClientConfigurationResponse) | GenerateClientConfiguration generates talosctl client configuration (talosconfig). |
<!-- end services -->

View File

@ -341,7 +341,7 @@ talosctl config add <context> [flags]
### SEE ALSO
* [talosctl config](#talosctl-config) - Manage the client configuration
* [talosctl config](#talosctl-config) - Manage the client configuration file (talosconfig)
## talosctl config context
@ -368,11 +368,11 @@ talosctl config context <context> [flags]
### SEE ALSO
* [talosctl config](#talosctl-config) - Manage the client configuration
* [talosctl config](#talosctl-config) - Manage the client configuration file (talosconfig)
## talosctl config contexts
List contexts defined in Talos config
List defined contexts
```
talosctl config contexts [flags]
@ -395,7 +395,7 @@ talosctl config contexts [flags]
### SEE ALSO
* [talosctl config](#talosctl-config) - Manage the client configuration
* [talosctl config](#talosctl-config) - Manage the client configuration file (talosconfig)
## talosctl config endpoint
@ -422,11 +422,11 @@ talosctl config endpoint <endpoint>... [flags]
### SEE ALSO
* [talosctl config](#talosctl-config) - Manage the client configuration
* [talosctl config](#talosctl-config) - Manage the client configuration file (talosconfig)
## talosctl config merge
Merge additional contexts from another Talos config into the default config
Merge additional contexts from another client configuration file
### Synopsis
@ -453,7 +453,36 @@ talosctl config merge <from> [flags]
### SEE ALSO
* [talosctl config](#talosctl-config) - Manage the client configuration
* [talosctl config](#talosctl-config) - Manage the client configuration file (talosconfig)
## talosctl config new
Generate a new client configuration file
```
talosctl config new [<path>] [flags]
```
### Options
```
--crt-ttl duration certificate TTL (default 87600h0m0s)
-h, --help help for new
--roles strings roles (default [os:admin])
```
### Options inherited from parent commands
```
--context string Context to be used in command
-e, --endpoints strings override default endpoints in Talos configuration
-n, --nodes strings target the specified nodes
--talosconfig string The path to the Talos configuration file (default "/home/user/.talos/config")
```
### SEE ALSO
* [talosctl config](#talosctl-config) - Manage the client configuration file (talosconfig)
## talosctl config node
@ -480,11 +509,11 @@ talosctl config node <endpoint>... [flags]
### SEE ALSO
* [talosctl config](#talosctl-config) - Manage the client configuration
* [talosctl config](#talosctl-config) - Manage the client configuration file (talosconfig)
## talosctl config
Manage the client configuration
Manage the client configuration file (talosconfig)
### Options
@ -506,9 +535,10 @@ Manage the client configuration
* [talosctl](#talosctl) - A CLI for out-of-band management of Kubernetes nodes created by Talos
* [talosctl config add](#talosctl-config-add) - Add a new context
* [talosctl config context](#talosctl-config-context) - Set the current context
* [talosctl config contexts](#talosctl-config-contexts) - List contexts defined in Talos config
* [talosctl config contexts](#talosctl-config-contexts) - List defined contexts
* [talosctl config endpoint](#talosctl-config-endpoint) - Set the endpoint(s) for the current context
* [talosctl config merge](#talosctl-config-merge) - Merge additional contexts from another Talos config into the default config
* [talosctl config merge](#talosctl-config-merge) - Merge additional contexts from another client configuration file
* [talosctl config new](#talosctl-config-new) - Generate a new client configuration file
* [talosctl config node](#talosctl-config-node) - Set the node(s) for the current context
## talosctl conformance kubernetes
@ -2142,7 +2172,7 @@ A CLI for out-of-band management of Kubernetes nodes created by Talos
* [talosctl bootstrap](#talosctl-bootstrap) - Bootstrap the etcd cluster on the specified node.
* [talosctl cluster](#talosctl-cluster) - A collection of commands for managing local docker-based or firecracker-based clusters
* [talosctl completion](#talosctl-completion) - Output shell completion code for the specified shell (bash or zsh)
* [talosctl config](#talosctl-config) - Manage the client configuration
* [talosctl config](#talosctl-config) - Manage the client configuration file (talosconfig)
* [talosctl conformance](#talosctl-conformance) - Run conformance tests
* [talosctl containers](#talosctl-containers) - List containers
* [talosctl convert-k8s](#talosctl-convert-k8s) - Convert Kubernetes control plane from self-hosted (bootkube) to Talos-managed (static pods).