feat: make GenerateConfiguration API reuse current node auth

Fixes: https://github.com/talos-systems/talos/issues/2819

Only if requested config type is not `TypeInit`.
This functionality will help implementing TUI installer cluster
extension workflow.

Signed-off-by: Artem Chernyshev <artem.0xD2@gmail.com>
This commit is contained in:
Artem Chernyshev 2020-11-19 18:26:50 +03:00 committed by talos-bot
parent b1c0f99c04
commit 2588e2960b
5 changed files with 187 additions and 68 deletions

View File

@ -108,6 +108,39 @@ func (suite *GenerateConfigSuite) TestGenerate() {
suite.Require().NotEmpty(context.Key)
suite.Require().Greater(len(context.Endpoints), 0)
suite.Require().EqualValues(context.Endpoints[0], config.Cluster().Endpoint().Hostname())
// now generate control plane join config
request.MachineConfig.Type = machineapi.MachineConfig_MachineType(machine.TypeControlPlane)
reply, err = suite.Client.GenerateConfiguration(
suite.ctx,
request,
)
suite.Require().NoError(err)
data = reply.GetData()
joinedConfig, err := configloader.NewFromBytes(data[0])
suite.Require().NoError(err)
suite.Require().EqualValues(request.MachineConfig.Type, joinedConfig.Machine().Type())
suite.Require().EqualValues(request.ConfigVersion, joinedConfig.Version())
suite.Require().EqualValues(request.ClusterConfig.Name, joinedConfig.Cluster().Name())
suite.Require().EqualValues(request.ClusterConfig.ControlPlane.Endpoint, joinedConfig.Cluster().Endpoint().String())
suite.Require().EqualValues(request.ClusterConfig.ClusterNetwork.DnsDomain, joinedConfig.Cluster().Network().DNSDomain())
suite.Require().EqualValues(fmt.Sprintf("%s:v%s", constants.KubeletImage, request.MachineConfig.KubernetesVersion), joinedConfig.Machine().Kubelet().Image())
suite.Require().EqualValues(request.MachineConfig.InstallConfig.InstallDisk, joinedConfig.Machine().Install().Disk())
suite.Require().EqualValues(request.MachineConfig.InstallConfig.InstallImage, joinedConfig.Machine().Install().Image())
suite.Require().EqualValues(request.MachineConfig.NetworkConfig.Hostname, joinedConfig.Machine().Network().Hostname())
suite.Require().EqualValues(config.Machine().Security().CA(), joinedConfig.Machine().Security().CA())
suite.Require().EqualValues(config.Machine().Security().Token(), joinedConfig.Machine().Security().Token())
suite.Require().EqualValues(config.Cluster().AESCBCEncryptionSecret(), joinedConfig.Cluster().AESCBCEncryptionSecret())
suite.Require().EqualValues(config.Cluster().CA(), joinedConfig.Cluster().CA())
suite.Require().EqualValues(config.Cluster().Token(), joinedConfig.Cluster().Token())
suite.Require().EqualValues(config.Cluster().Etcd().CA(), config.Cluster().Etcd().CA())
}
func init() {

View File

@ -8,19 +8,22 @@ import (
"context"
"fmt"
"net/url"
"os"
"github.com/talos-systems/talos/pkg/machinery/api/machine"
"github.com/talos-systems/talos/pkg/machinery/config"
"github.com/talos-systems/talos/pkg/machinery/config/configloader"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/generate"
v1alpha1machine "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine"
"github.com/talos-systems/talos/pkg/machinery/constants"
)
// Generate config for GenerateConfiguration grpc.
//
// nolint:gocyclo
func Generate(ctx context.Context, in *machine.GenerateConfigurationRequest) (reply *machine.GenerateConfigurationResponse, err error) {
var config config.Provider
var c config.Provider
if in.MachineConfig == nil || in.ClusterConfig == nil || in.ClusterConfig.ControlPlane == nil {
return nil, fmt.Errorf("invalid generate request")
@ -60,12 +63,29 @@ func Generate(ctx context.Context, in *machine.GenerateConfigurationRequest) (re
input *generate.Input
cfgBytes []byte
taloscfgBytes []byte
baseConfig config.Provider
secrets *generate.SecretsBundle
)
baseConfig, err = configloader.NewFromFile(constants.ConfigPath)
switch {
case os.IsNotExist(err):
secrets, err = generate.NewSecretsBundle()
if err != nil {
return nil, err
}
case err != nil:
return nil, err
default:
secrets = generate.NewSecretsBundleFromConfig(baseConfig)
}
input, err = generate.NewInput(
in.ClusterConfig.Name,
in.ClusterConfig.ControlPlane.Endpoint,
in.MachineConfig.KubernetesVersion,
secrets,
options...,
)
@ -73,7 +93,7 @@ func Generate(ctx context.Context, in *machine.GenerateConfigurationRequest) (re
return nil, err
}
config, err = generate.Config(
c, err = generate.Config(
machineType,
input,
)
@ -82,7 +102,7 @@ func Generate(ctx context.Context, in *machine.GenerateConfigurationRequest) (re
return nil, err
}
cfgBytes, err = config.Bytes()
cfgBytes, err = c.Bytes()
if err != nil {
return nil, err

View File

@ -80,12 +80,18 @@ func NewConfigBundle(opts ...Option) (*v1alpha1.ConfigBundle, error) {
fmt.Println("generating PKI and tokens")
}
secrets, err := generate.NewSecretsBundle()
if err != nil {
return bundle, err
}
var input *generate.Input
input, err := generate.NewInput(
input, err = generate.NewInput(
options.InputOptions.ClusterName,
options.InputOptions.Endpoint,
options.InputOptions.KubeVersion,
secrets,
options.InputOptions.GenOptions...,
)
if err != nil {

View File

@ -10,6 +10,7 @@ import (
stdlibx509 "crypto/x509"
"encoding/pem"
"errors"
"fmt"
"net"
"net/url"
"time"
@ -17,6 +18,7 @@ import (
"github.com/talos-systems/crypto/x509"
tnet "github.com/talos-systems/net"
"github.com/talos-systems/talos/pkg/machinery/config"
"github.com/talos-systems/talos/pkg/machinery/config/internal/cis"
v1alpha1 "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine"
@ -132,7 +134,7 @@ type Certs struct {
OS *x509.PEMEncodedCertificateAndKey
}
// Secrets holds the senesitve kubeadm data.
// Secrets holds the sensitive kubeadm data.
type Secrets struct {
BootstrapToken string
AESCBCEncryptionSecret string
@ -143,6 +145,114 @@ type TrustdInfo struct {
Token string
}
// SecretsBundle holds trustd, kubeadm and certs information.
type SecretsBundle struct {
Secrets *Secrets
TrustdInfo *TrustdInfo
Certs *Certs
}
// NewSecretsBundle creates secrets bundle generating all secrets.
func NewSecretsBundle() (*SecretsBundle, error) {
var (
etcd *x509.CertificateAuthority
kubernetesCA *x509.CertificateAuthority
talosCA *x509.CertificateAuthority
trustdInfo *TrustdInfo
kubeadmTokens *Secrets
err error
)
etcd, err = NewEtcdCA()
if err != nil {
return nil, err
}
kubernetesCA, err = NewKubernetesCA()
if err != nil {
return nil, err
}
talosCA, err = NewTalosCA()
if err != nil {
return nil, err
}
if err != nil {
return nil, err
}
kubeadmTokens = &Secrets{}
// Gen trustd token strings
kubeadmTokens.BootstrapToken, err = genToken(6, 16)
if err != nil {
return nil, err
}
kubeadmTokens.AESCBCEncryptionSecret, err = cis.CreateEncryptionToken()
if err != nil {
return nil, err
}
trustdInfo = &TrustdInfo{}
// Gen trustd token strings
trustdInfo.Token, err = genToken(6, 16)
if err != nil {
return nil, err
}
return &SecretsBundle{
Secrets: kubeadmTokens,
TrustdInfo: trustdInfo,
Certs: &Certs{
Etcd: &x509.PEMEncodedCertificateAndKey{
Crt: etcd.CrtPEM,
Key: etcd.KeyPEM,
},
K8s: &x509.PEMEncodedCertificateAndKey{
Crt: kubernetesCA.CrtPEM,
Key: kubernetesCA.KeyPEM,
},
OS: &x509.PEMEncodedCertificateAndKey{
Crt: talosCA.CrtPEM,
Key: talosCA.KeyPEM,
},
},
}, nil
}
// NewSecretsBundleFromConfig creates secrets bundle using existing config.
func NewSecretsBundleFromConfig(c config.Provider) *SecretsBundle {
certs := &Certs{
K8s: c.Cluster().CA(),
Etcd: c.Cluster().Etcd().CA(),
OS: c.Machine().Security().CA(),
}
trustd := &TrustdInfo{
Token: c.Machine().Security().Token(),
}
bootstrapToken := fmt.Sprintf(
"%s.%s",
c.Cluster().Token().ID(),
c.Cluster().Token().Secret(),
)
secrets := &Secrets{
AESCBCEncryptionSecret: c.Cluster().AESCBCEncryptionSecret(),
BootstrapToken: bootstrapToken,
}
return &SecretsBundle{
Secrets: secrets,
TrustdInfo: trustd,
Certs: certs,
}
}
// NewEtcdCA generates a CA for the Etcd PKI.
func NewEtcdCA() (ca *x509.CertificateAuthority, err error) {
opts := []x509.Option{
@ -211,7 +321,7 @@ func NewAdminCertificateAndKey(crt, key []byte, loopback string) (p *x509.PEMEnc
// NewInput generates the sensitive data required to generate all config
// types.
// nolint: dupl,gocyclo
func NewInput(clustername, endpoint, kubernetesVersion string, opts ...GenOption) (input *Input, err error) {
func NewInput(clustername, endpoint, kubernetesVersion string, secrets *SecretsBundle, opts ...GenOption) (input *Input, err error) {
options := DefaultGenOptions()
for _, opt := range opts {
@ -232,68 +342,16 @@ func NewInput(clustername, endpoint, kubernetesVersion string, opts ...GenOption
serviceNet = constants.DefaultIPv4ServiceNet
}
// Gen trustd token strings
kubeadmBootstrapToken, err := genToken(6, 16)
secrets.Certs.Admin, err = NewAdminCertificateAndKey(
secrets.Certs.OS.Crt,
secrets.Certs.OS.Key,
loopback,
)
if err != nil {
return nil, err
}
aescbcEncryptionSecret, err := cis.CreateEncryptionToken()
if err != nil {
return nil, err
}
// Gen trustd token strings
trustdToken, err := genToken(6, 16)
if err != nil {
return nil, err
}
kubeadmTokens := &Secrets{
BootstrapToken: kubeadmBootstrapToken,
AESCBCEncryptionSecret: aescbcEncryptionSecret,
}
trustdInfo := &TrustdInfo{
Token: trustdToken,
}
etcdCA, err := NewEtcdCA()
if err != nil {
return nil, err
}
kubernetesCA, err := NewKubernetesCA()
if err != nil {
return nil, err
}
talosCA, err := NewTalosCA()
if err != nil {
return nil, err
}
admin, err := NewAdminCertificateAndKey(talosCA.CrtPEM, talosCA.KeyPEM, loopback)
if err != nil {
return nil, err
}
certs := &Certs{
Admin: admin,
Etcd: &x509.PEMEncodedCertificateAndKey{
Crt: etcdCA.CrtPEM,
Key: etcdCA.KeyPEM,
},
K8s: &x509.PEMEncodedCertificateAndKey{
Crt: kubernetesCA.CrtPEM,
Key: kubernetesCA.KeyPEM,
},
OS: &x509.PEMEncodedCertificateAndKey{
Crt: talosCA.CrtPEM,
Key: talosCA.KeyPEM,
},
}
var additionalSubjectAltNames []string
var additionalMachineCertSANs []string
@ -310,7 +368,7 @@ func NewInput(clustername, endpoint, kubernetesVersion string, opts ...GenOption
}
input = &Input{
Certs: certs,
Certs: secrets.Certs,
ControlPlaneEndpoint: endpoint,
PodNet: []string{podNet},
ServiceNet: []string{serviceNet},
@ -318,8 +376,8 @@ func NewInput(clustername, endpoint, kubernetesVersion string, opts ...GenOption
ClusterName: clustername,
Architecture: options.Architecture,
KubernetesVersion: kubernetesVersion,
Secrets: kubeadmTokens,
TrustdInfo: trustdInfo,
Secrets: secrets.Secrets,
TrustdInfo: secrets.TrustdInfo,
AdditionalSubjectAltNames: additionalSubjectAltNames,
AdditionalMachineCertSANs: additionalMachineCertSANs,
InstallDisk: options.InstallDisk,

View File

@ -26,7 +26,9 @@ func TestGenerateSuite(t *testing.T) {
func (suite *GenerateSuite) SetupSuite() {
var err error
suite.input, err = genv1alpha1.NewInput("test", "10.0.1.5", constants.DefaultKubernetesVersion)
secrets, err := genv1alpha1.NewSecretsBundle()
suite.Require().NoError(err)
suite.input, err = genv1alpha1.NewInput("test", "10.0.1.5", constants.DefaultKubernetesVersion, secrets)
suite.Require().NoError(err)
}