mirror of
				https://github.com/siderolabs/talos.git
				synced 2025-10-31 00:11:36 +01:00 
			
		
		
		
	Fixes #8753 There seems to be a problem in the machine config anyways, as `machine.ca.crt` is missing for the worker (this should break `apid` connectivity), but still Talos controller shouldn't enter a panic loop. Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
		
			
				
	
	
		
			201 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			7.0 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"
 | |
| 	"errors"
 | |
| 	"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/crypto/x509"
 | |
| 	"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 errors.New("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.
 | |
| 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://127.0.0.1:%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 errors.New("missing cluster.aggregatorCA secret")
 | |
| 				}
 | |
| 
 | |
| 				k8sSecrets.IssuingCA = cfgProvider.Cluster().IssuingCA()
 | |
| 				k8sSecrets.AcceptedCAs = cfgProvider.Cluster().AcceptedCAs()
 | |
| 
 | |
| 				if k8sSecrets.IssuingCA != nil {
 | |
| 					k8sSecrets.AcceptedCAs = append(k8sSecrets.AcceptedCAs, &x509.PEMEncodedCertificate{
 | |
| 						Crt: k8sSecrets.IssuingCA.Crt,
 | |
| 					})
 | |
| 				}
 | |
| 
 | |
| 				if len(k8sSecrets.IssuingCA.Key) == 0 {
 | |
| 					// drop incomplete issuing CA, as the machine config for workers contains just the cert
 | |
| 					k8sSecrets.IssuingCA = nil
 | |
| 				}
 | |
| 
 | |
| 				if len(k8sSecrets.AcceptedCAs) == 0 {
 | |
| 					return errors.New("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.IssuingCA = cfgProvider.Machine().Security().IssuingCA()
 | |
| 				osSecrets.AcceptedCAs = cfgProvider.Machine().Security().AcceptedCAs()
 | |
| 
 | |
| 				if osSecrets.IssuingCA != nil {
 | |
| 					osSecrets.AcceptedCAs = append(osSecrets.AcceptedCAs, &x509.PEMEncodedCertificate{
 | |
| 						Crt: osSecrets.IssuingCA.Crt,
 | |
| 					})
 | |
| 
 | |
| 					if len(osSecrets.IssuingCA.Key) == 0 {
 | |
| 						// drop incomplete issuing CA, as the machine config for workers contains just the cert
 | |
| 						osSecrets.IssuingCA = nil
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				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
 | |
| 			},
 | |
| 		},
 | |
| 	)
 | |
| }
 |