Serve secrets from kops-controller for nodes without state store access

This commit is contained in:
Ciprian Hacman 2022-11-11 14:57:28 +02:00
parent 18b5dcd297
commit 61eaeddb9b
9 changed files with 63 additions and 18 deletions

View File

@ -245,6 +245,9 @@ func addNodeController(mgr manager.Manager, opt *config.Options) error {
if opt.ConfigBase == "" {
return fmt.Errorf("must specify configBase")
}
if opt.SecretStore == "" {
return fmt.Errorf("must specify secretStore")
}
nodeController, err := controllers.NewLegacyNodeReconciler(mgr, opt.ConfigBase, legacyIdentifier)
if err != nil {

View File

@ -25,6 +25,7 @@ import (
type Options struct {
Cloud string `json:"cloud,omitempty"`
ConfigBase string `json:"configBase,omitempty"`
SecretStore string `json:"secretStore,omitempty"`
Server *ServerOptions `json:"server,omitempty"`
CacheNodeidentityInfo bool `json:"cacheNodeidentityInfo,omitempty"`

View File

@ -61,5 +61,21 @@ func (s *Server) getNodeConfig(ctx context.Context, req *nodeup.BootstrapRequest
nodeConfig.NodeupConfig = string(b)
}
{
secretIDs := []string{
"dockerconfig",
}
nodeConfig.NodeSecrets = make(map[string][]byte)
for _, id := range secretIDs {
secret, err := s.secretStore.FindSecret(id)
if err != nil {
return nil, fmt.Errorf("error loading secret %q: %w", id, err)
}
if secret != nil && secret.Data != nil {
nodeConfig.NodeSecrets[id] = secret.Data
}
}
}
return nodeConfig, nil
}

View File

@ -38,6 +38,7 @@ import (
"k8s.io/kops/pkg/pki"
"k8s.io/kops/pkg/rbac"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/secrets"
"k8s.io/kops/util/pkg/vfs"
)
@ -48,6 +49,7 @@ type Server struct {
server *http.Server
verifier bootstrap.Verifier
keystore pki.Keystore
secretStore fi.SecretStore
// configBase is the base of the configuration storage.
configBase vfs.Path
@ -71,10 +73,16 @@ func NewServer(opt *config.Options, verifier bootstrap.Verifier) (*Server, error
configBase, err := vfs.Context.BuildVfsPath(opt.ConfigBase)
if err != nil {
return nil, fmt.Errorf("cannot parse ConfigBase %q: %v", opt.ConfigBase, err)
return nil, fmt.Errorf("cannot parse ConfigBase %q: %w", opt.ConfigBase, err)
}
s.configBase = configBase
p, err := vfs.Context.BuildVfsPath(opt.SecretStore)
if err != nil {
return nil, fmt.Errorf("cannot parse SecretStore %q: %w", opt.SecretStore, err)
}
s.secretStore = secrets.NewVFSSecretStore(nil, p)
r := http.NewServeMux()
r.Handle("/bootstrap", http.HandlerFunc(s.bootstrap))
server.Handler = recovery(r)

View File

@ -35,7 +35,7 @@ type BootstrapRequest struct {
// BootstrapResponse is a response to a BootstrapRequest.
type BootstrapResponse struct {
// Certs are the issued certificates.
Certs map[string]string
Certs map[string]string `json:"Certs,omitempty"`
// NodeConfig contains the node configuration, if IncludeNodeConfig is set.
NodeConfig *NodeConfig `json:"nodeConfig,omitempty"`
@ -48,6 +48,9 @@ type NodeConfig struct {
// NodeupConfig holds the nodeup.Config for the node's instance group.
NodeupConfig string `json:"nodeupConfig,omitempty"`
// NodeSecrets holds the secrets for the node (like `dockerconfig`).
NodeSecrets map[string][]byte `json:"nodeSecrets,omitempty"`
}
// NodeConfigCertificate holds a certificate that the node needs to boot.

View File

@ -19,25 +19,31 @@ package configserver
import (
"fmt"
"k8s.io/kops/pkg/apis/nodeup"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/util/pkg/vfs"
)
// configserverSecretStore is a SecretStore backed by the config server.
type configserverSecretStore struct {
nodeConfig *nodeup.NodeConfig
nodeSecrets map[string][]byte
}
func NewSecretStore(nodeConfig *nodeup.NodeConfig) fi.SecretStore {
func NewSecretStore(nodeSecrets map[string][]byte) fi.SecretStore {
return &configserverSecretStore{
nodeConfig: nodeConfig,
nodeSecrets: nodeSecrets,
}
}
// Secret implements fi.SecretStore
func (s *configserverSecretStore) Secret(id string) (*fi.Secret, error) {
return nil, fmt.Errorf("Secret not supported by configserverSecretStore")
secret, err := s.FindSecret(id)
if err != nil {
return nil, err
}
if secret == nil {
return nil, fmt.Errorf("secret %q not found", id)
}
return secret, nil
}
// DeleteSecret implements fi.SecretStore
@ -47,7 +53,14 @@ func (s *configserverSecretStore) DeleteSecret(id string) error {
// FindSecret implements fi.SecretStore
func (s *configserverSecretStore) FindSecret(id string) (*fi.Secret, error) {
return nil, fmt.Errorf("FindSecret not supported by configserverSecretStore")
secretBytes, ok := s.nodeSecrets[id]
if !ok {
return nil, nil
}
secret := &fi.Secret{
Data: secretBytes,
}
return secret, nil
}
// GetOrCreateSecret implements fi.SecretStore

View File

@ -584,6 +584,7 @@ func (tf *TemplateFunctions) KopsControllerConfig() (string, error) {
config := &kopscontrollerconfig.Options{
Cloud: string(cluster.Spec.GetCloudProvider()),
ConfigBase: cluster.Spec.ConfigBase,
SecretStore: cluster.Spec.SecretStore,
}
if featureflag.CacheNodeidentityInfo.Enabled() {

View File

@ -235,7 +235,7 @@ func (c *NodeUpCommand) Run(out io.Writer) error {
var secretStore fi.SecretStore
var keyStore fi.Keystore
if nodeConfig != nil {
modelContext.SecretStore = configserver.NewSecretStore(nodeConfig)
modelContext.SecretStore = configserver.NewSecretStore(nodeConfig.NodeSecrets)
} else if c.cluster.Spec.SecretStore != "" {
klog.Infof("Building SecretStore at %q", c.cluster.Spec.SecretStore)
p, err := vfs.Context.BuildVfsPath(c.cluster.Spec.SecretStore)

View File

@ -133,7 +133,7 @@ func (c *VFSSecretStore) Secret(id string) (*fi.Secret, error) {
return nil, err
}
if s == nil {
return nil, fmt.Errorf("Secret not found: %q", id)
return nil, fmt.Errorf("secret %q not found", id)
}
return s, nil
}