feat: implement talosctl config new
command
Refs #3421. Signed-off-by: Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
This commit is contained in:
committed by
talos-bot
parent
fa15a6687f
commit
f63ab9dd9b
@ -5,7 +5,6 @@
|
||||
!hack
|
||||
!internal
|
||||
!pkg
|
||||
!vendor
|
||||
!website
|
||||
!.golangci.yml
|
||||
!.markdownlint.json
|
||||
|
@ -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";
|
||||
|
@ -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);
|
||||
|
@ -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";
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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";
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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";
|
||||
|
@ -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";
|
||||
|
@ -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}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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{
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
2
go.mod
@ -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
4
go.sum
@ -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=
|
||||
|
@ -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(
|
||||
|
@ -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...)
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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{
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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 (
|
||||
|
@ -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
@ -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{
|
||||
{
|
||||
|
@ -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 (
|
||||
|
@ -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 (
|
||||
|
@ -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 (
|
||||
|
@ -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 (
|
||||
|
@ -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 (
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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=
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()))
|
||||
}
|
||||
|
@ -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
|
||||
|
114
prototool.yaml
114
prototool.yaml
@ -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:
|
||||
|
@ -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 -->
|
||||
|
||||
|
@ -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).
|
||||
|
Reference in New Issue
Block a user