mirror of https://github.com/kubernetes/kops.git
Serve secrets from kops-controller for nodes without state store access
This commit is contained in:
parent
18b5dcd297
commit
61eaeddb9b
|
|
@ -245,6 +245,9 @@ func addNodeController(mgr manager.Manager, opt *config.Options) error {
|
||||||
if opt.ConfigBase == "" {
|
if opt.ConfigBase == "" {
|
||||||
return fmt.Errorf("must specify configBase")
|
return fmt.Errorf("must specify configBase")
|
||||||
}
|
}
|
||||||
|
if opt.SecretStore == "" {
|
||||||
|
return fmt.Errorf("must specify secretStore")
|
||||||
|
}
|
||||||
|
|
||||||
nodeController, err := controllers.NewLegacyNodeReconciler(mgr, opt.ConfigBase, legacyIdentifier)
|
nodeController, err := controllers.NewLegacyNodeReconciler(mgr, opt.ConfigBase, legacyIdentifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Cloud string `json:"cloud,omitempty"`
|
Cloud string `json:"cloud,omitempty"`
|
||||||
ConfigBase string `json:"configBase,omitempty"`
|
ConfigBase string `json:"configBase,omitempty"`
|
||||||
|
SecretStore string `json:"secretStore,omitempty"`
|
||||||
Server *ServerOptions `json:"server,omitempty"`
|
Server *ServerOptions `json:"server,omitempty"`
|
||||||
CacheNodeidentityInfo bool `json:"cacheNodeidentityInfo,omitempty"`
|
CacheNodeidentityInfo bool `json:"cacheNodeidentityInfo,omitempty"`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,5 +61,21 @@ func (s *Server) getNodeConfig(ctx context.Context, req *nodeup.BootstrapRequest
|
||||||
nodeConfig.NodeupConfig = string(b)
|
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
|
return nodeConfig, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,16 +38,18 @@ import (
|
||||||
"k8s.io/kops/pkg/pki"
|
"k8s.io/kops/pkg/pki"
|
||||||
"k8s.io/kops/pkg/rbac"
|
"k8s.io/kops/pkg/rbac"
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
|
"k8s.io/kops/upup/pkg/fi/secrets"
|
||||||
"k8s.io/kops/util/pkg/vfs"
|
"k8s.io/kops/util/pkg/vfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
opt *config.Options
|
opt *config.Options
|
||||||
certNames sets.String
|
certNames sets.String
|
||||||
keypairIDs map[string]string
|
keypairIDs map[string]string
|
||||||
server *http.Server
|
server *http.Server
|
||||||
verifier bootstrap.Verifier
|
verifier bootstrap.Verifier
|
||||||
keystore pki.Keystore
|
keystore pki.Keystore
|
||||||
|
secretStore fi.SecretStore
|
||||||
|
|
||||||
// configBase is the base of the configuration storage.
|
// configBase is the base of the configuration storage.
|
||||||
configBase vfs.Path
|
configBase vfs.Path
|
||||||
|
|
@ -71,10 +73,16 @@ func NewServer(opt *config.Options, verifier bootstrap.Verifier) (*Server, error
|
||||||
|
|
||||||
configBase, err := vfs.Context.BuildVfsPath(opt.ConfigBase)
|
configBase, err := vfs.Context.BuildVfsPath(opt.ConfigBase)
|
||||||
if err != nil {
|
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
|
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 := http.NewServeMux()
|
||||||
r.Handle("/bootstrap", http.HandlerFunc(s.bootstrap))
|
r.Handle("/bootstrap", http.HandlerFunc(s.bootstrap))
|
||||||
server.Handler = recovery(r)
|
server.Handler = recovery(r)
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ type BootstrapRequest struct {
|
||||||
// BootstrapResponse is a response to a BootstrapRequest.
|
// BootstrapResponse is a response to a BootstrapRequest.
|
||||||
type BootstrapResponse struct {
|
type BootstrapResponse struct {
|
||||||
// Certs are the issued certificates.
|
// 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 contains the node configuration, if IncludeNodeConfig is set.
|
||||||
NodeConfig *NodeConfig `json:"nodeConfig,omitempty"`
|
NodeConfig *NodeConfig `json:"nodeConfig,omitempty"`
|
||||||
|
|
@ -48,6 +48,9 @@ type NodeConfig struct {
|
||||||
|
|
||||||
// NodeupConfig holds the nodeup.Config for the node's instance group.
|
// NodeupConfig holds the nodeup.Config for the node's instance group.
|
||||||
NodeupConfig string `json:"nodeupConfig,omitempty"`
|
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.
|
// NodeConfigCertificate holds a certificate that the node needs to boot.
|
||||||
|
|
|
||||||
|
|
@ -19,25 +19,31 @@ package configserver
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"k8s.io/kops/pkg/apis/nodeup"
|
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
"k8s.io/kops/util/pkg/vfs"
|
"k8s.io/kops/util/pkg/vfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// configserverSecretStore is a SecretStore backed by the config server.
|
// configserverSecretStore is a SecretStore backed by the config server.
|
||||||
type configserverSecretStore struct {
|
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{
|
return &configserverSecretStore{
|
||||||
nodeConfig: nodeConfig,
|
nodeSecrets: nodeSecrets,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Secret implements fi.SecretStore
|
// Secret implements fi.SecretStore
|
||||||
func (s *configserverSecretStore) Secret(id string) (*fi.Secret, error) {
|
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
|
// DeleteSecret implements fi.SecretStore
|
||||||
|
|
@ -47,7 +53,14 @@ func (s *configserverSecretStore) DeleteSecret(id string) error {
|
||||||
|
|
||||||
// FindSecret implements fi.SecretStore
|
// FindSecret implements fi.SecretStore
|
||||||
func (s *configserverSecretStore) FindSecret(id string) (*fi.Secret, error) {
|
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
|
// GetOrCreateSecret implements fi.SecretStore
|
||||||
|
|
|
||||||
|
|
@ -582,8 +582,9 @@ func (tf *TemplateFunctions) KopsControllerConfig() (string, error) {
|
||||||
cluster := tf.Cluster
|
cluster := tf.Cluster
|
||||||
|
|
||||||
config := &kopscontrollerconfig.Options{
|
config := &kopscontrollerconfig.Options{
|
||||||
Cloud: string(cluster.Spec.GetCloudProvider()),
|
Cloud: string(cluster.Spec.GetCloudProvider()),
|
||||||
ConfigBase: cluster.Spec.ConfigBase,
|
ConfigBase: cluster.Spec.ConfigBase,
|
||||||
|
SecretStore: cluster.Spec.SecretStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
if featureflag.CacheNodeidentityInfo.Enabled() {
|
if featureflag.CacheNodeidentityInfo.Enabled() {
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,7 @@ func (c *NodeUpCommand) Run(out io.Writer) error {
|
||||||
var secretStore fi.SecretStore
|
var secretStore fi.SecretStore
|
||||||
var keyStore fi.Keystore
|
var keyStore fi.Keystore
|
||||||
if nodeConfig != nil {
|
if nodeConfig != nil {
|
||||||
modelContext.SecretStore = configserver.NewSecretStore(nodeConfig)
|
modelContext.SecretStore = configserver.NewSecretStore(nodeConfig.NodeSecrets)
|
||||||
} else if c.cluster.Spec.SecretStore != "" {
|
} else if c.cluster.Spec.SecretStore != "" {
|
||||||
klog.Infof("Building SecretStore at %q", c.cluster.Spec.SecretStore)
|
klog.Infof("Building SecretStore at %q", c.cluster.Spec.SecretStore)
|
||||||
p, err := vfs.Context.BuildVfsPath(c.cluster.Spec.SecretStore)
|
p, err := vfs.Context.BuildVfsPath(c.cluster.Spec.SecretStore)
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ func (c *VFSSecretStore) Secret(id string) (*fi.Secret, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return nil, fmt.Errorf("Secret not found: %q", id)
|
return nil, fmt.Errorf("secret %q not found", id)
|
||||||
}
|
}
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue