Andrey Smirnov 544cb4fe7d
refactor: accept partial machine configuration
This refactors code to handle partial machine config - only multi-doc
without v1alpha1 config.

This uses improvements from
https://github.com/cosi-project/runtime/pull/300:

* where possible, use `TransformController`
* use integrated tracker to reduce boilerplate

Sometimes fix/rewrite tests where applicable.

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
2023-07-27 17:00:42 +04:00

177 lines
6.1 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package secrets
import (
"context"
"fmt"
"net/netip"
"net/url"
"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/controller/generic"
"github.com/cosi-project/runtime/pkg/controller/generic/transform"
"github.com/siderolabs/gen/optional"
"go.uber.org/zap"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/machinery/resources/config"
"github.com/siderolabs/talos/pkg/machinery/resources/secrets"
)
func rootMapFunc[Output generic.ResourceWithRD](output Output, requireControlPlane bool) func(cfg *config.MachineConfig) optional.Optional[Output] {
return func(cfg *config.MachineConfig) optional.Optional[Output] {
if cfg.Metadata().ID() != config.V1Alpha1ID {
return optional.None[Output]()
}
if cfg.Config().Cluster() == nil || cfg.Config().Machine() == nil {
return optional.None[Output]()
}
if requireControlPlane && !cfg.Config().Machine().Type().IsControlPlane() {
return optional.None[Output]()
}
return optional.Some(output)
}
}
// RootEtcdController manages secrets.EtcdRoot based on configuration.
type RootEtcdController = transform.Controller[*config.MachineConfig, *secrets.EtcdRoot]
// NewRootEtcdController instanciates the controller.
func NewRootEtcdController() *RootEtcdController {
return transform.NewController(
transform.Settings[*config.MachineConfig, *secrets.EtcdRoot]{
Name: "secrets.RootEtcdController",
MapMetadataOptionalFunc: rootMapFunc(secrets.NewEtcdRoot(secrets.EtcdRootID), true),
TransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *secrets.EtcdRoot) error {
cfgProvider := cfg.Config()
etcdSecrets := res.TypedSpec()
etcdSecrets.EtcdCA = cfgProvider.Cluster().Etcd().CA()
if etcdSecrets.EtcdCA == nil {
return fmt.Errorf("missing cluster.etcdCA secret")
}
return nil
},
},
)
}
// RootKubernetesController manages secrets.KubernetesRoot based on configuration.
type RootKubernetesController = transform.Controller[*config.MachineConfig, *secrets.KubernetesRoot]
// NewRootKubernetesController instanciates the controller.
//
//nolint:gocyclo
func NewRootKubernetesController() *RootKubernetesController {
return transform.NewController(
transform.Settings[*config.MachineConfig, *secrets.KubernetesRoot]{
Name: "secrets.RootKubernetesController",
MapMetadataOptionalFunc: rootMapFunc(secrets.NewKubernetesRoot(secrets.KubernetesRootID), true),
TransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *secrets.KubernetesRoot) error {
cfgProvider := cfg.Config()
k8sSecrets := res.TypedSpec()
var (
err error
localEndpoint *url.URL
)
if cfgProvider.Machine().Features().KubePrism().Enabled() {
localEndpoint, err = url.Parse(fmt.Sprintf("https://localhost:%d", cfgProvider.Machine().Features().KubePrism().Port()))
if err != nil {
return err
}
} else {
localEndpoint, err = url.Parse(fmt.Sprintf("https://localhost:%d", cfgProvider.Cluster().LocalAPIServerPort()))
if err != nil {
return err
}
}
k8sSecrets.Name = cfgProvider.Cluster().Name()
k8sSecrets.Endpoint = cfgProvider.Cluster().Endpoint()
k8sSecrets.LocalEndpoint = localEndpoint
k8sSecrets.CertSANs = cfgProvider.Cluster().CertSANs()
k8sSecrets.DNSDomain = cfgProvider.Cluster().Network().DNSDomain()
k8sSecrets.APIServerIPs, err = cfgProvider.Cluster().Network().APIServerIPs()
if err != nil {
return fmt.Errorf("error building API service IPs: %w", err)
}
k8sSecrets.AggregatorCA = cfgProvider.Cluster().AggregatorCA()
if k8sSecrets.AggregatorCA == nil {
return fmt.Errorf("missing cluster.aggregatorCA secret")
}
k8sSecrets.CA = cfgProvider.Cluster().CA()
if k8sSecrets.CA == nil {
return fmt.Errorf("missing cluster.CA secret")
}
k8sSecrets.ServiceAccount = cfgProvider.Cluster().ServiceAccount()
k8sSecrets.AESCBCEncryptionSecret = cfgProvider.Cluster().AESCBCEncryptionSecret()
k8sSecrets.SecretboxEncryptionSecret = cfgProvider.Cluster().SecretboxEncryptionSecret()
k8sSecrets.BootstrapTokenID = cfgProvider.Cluster().Token().ID()
k8sSecrets.BootstrapTokenSecret = cfgProvider.Cluster().Token().Secret()
return nil
},
},
)
}
// RootOSController manages secrets.OSRoot based on configuration.
type RootOSController = transform.Controller[*config.MachineConfig, *secrets.OSRoot]
// NewRootOSController instanciates the controller.
func NewRootOSController() *RootOSController {
return transform.NewController(
transform.Settings[*config.MachineConfig, *secrets.OSRoot]{
Name: "secrets.RootOSController",
MapMetadataOptionalFunc: rootMapFunc(secrets.NewOSRoot(secrets.OSRootID), false),
TransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *secrets.OSRoot) error {
cfgProvider := cfg.Config()
osSecrets := res.TypedSpec()
osSecrets.CA = cfgProvider.Machine().Security().CA()
osSecrets.CertSANIPs = nil
osSecrets.CertSANDNSNames = nil
for _, san := range cfgProvider.Machine().Security().CertSANs() {
if ip, err := netip.ParseAddr(san); err == nil {
osSecrets.CertSANIPs = append(osSecrets.CertSANIPs, ip)
} else {
osSecrets.CertSANDNSNames = append(osSecrets.CertSANDNSNames, san)
}
}
if cfgProvider.Machine().Features().KubernetesTalosAPIAccess().Enabled() {
// add Kubernetes Talos service name to the list of SANs
osSecrets.CertSANDNSNames = append(osSecrets.CertSANDNSNames,
constants.KubernetesTalosAPIServiceName,
constants.KubernetesTalosAPIServiceName+"."+constants.KubernetesTalosAPIServiceNamespace,
)
}
osSecrets.Token = cfgProvider.Machine().Security().Token()
return nil
},
},
)
}