Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP]When kubelet enable rotate-certificates and bootstrap, request CSR in foreground #112240

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 14 additions & 2 deletions cmd/kubelet/app/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -822,8 +822,8 @@ func buildKubeletClientConfig(ctx context.Context, s *options.KubeletServer, tp
// which provides a high powered kubeconfig on the master with cert/key data, we must
// bootstrap the cert manager with the contents of the initial client config.

klog.InfoS("Client rotation is on, will bootstrap in background")
certConfig, clientConfig, err := bootstrap.LoadClientConfig(s.KubeConfig, s.BootstrapKubeconfig, s.CertDirectory)
klog.InfoS("Client rotation is on")
certConfig, clientConfig, bootstraping, err := bootstrap.LoadClientConfig(s.KubeConfig, s.BootstrapKubeconfig, s.CertDirectory)
if err != nil {
return nil, nil, err
}
Expand All @@ -838,6 +838,18 @@ func buildKubeletClientConfig(ctx context.Context, s *options.KubeletServer, tp
return nil, nil, err
}

if bootstraping {
klog.InfoS("When bootstraping, waiting the client rotation for the first time")
rotated, err := clientCertificateManager.RotateCerts()
if err != nil {
klog.Warningf("When bootstraping, failed to rotate certs: %v", err)
} else if !rotated {
klog.Warning("Failed to rotate certs when bootstrap")
} else {
klog.InfoS("Succeeded to rotate certs when bootstrap")
}
}

legacyregistry.RawMustRegister(metrics.NewGaugeFunc(
&metrics.GaugeOpts{
Subsystem: kubeletmetrics.KubeletSubsystem,
Expand Down
20 changes: 10 additions & 10 deletions pkg/kubelet/certificate/bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,50 +55,50 @@ const tmpPrivateKeyFile = "kubelet-client.key.tmp"
// kubeconfigPath on disk is populated based on bootstrapPath but pointing to the location of the client cert
// in certDir. This preserves the historical behavior of bootstrapping where on subsequent restarts the
// most recent client cert is used to request new client certs instead of the initial token.
func LoadClientConfig(kubeconfigPath, bootstrapPath, certDir string) (certConfig, userConfig *restclient.Config, err error) {
func LoadClientConfig(kubeconfigPath, bootstrapPath, certDir string) (certConfig, userConfig *restclient.Config, bootstraping bool, err error) {
if len(bootstrapPath) == 0 {
clientConfig, err := loadRESTClientConfig(kubeconfigPath)
if err != nil {
return nil, nil, fmt.Errorf("unable to load kubeconfig: %v", err)
return nil, nil, false, fmt.Errorf("unable to load kubeconfig: %v", err)
}
klog.V(2).InfoS("No bootstrapping requested, will use kubeconfig")
return clientConfig, restclient.CopyConfig(clientConfig), nil
return clientConfig, restclient.CopyConfig(clientConfig), false, nil
}

store, err := certificate.NewFileStore("kubelet-client", certDir, certDir, "", "")
if err != nil {
return nil, nil, fmt.Errorf("unable to build bootstrap cert store")
return nil, nil, false, fmt.Errorf("unable to build bootstrap cert store")
}

ok, err := isClientConfigStillValid(kubeconfigPath)
if err != nil {
return nil, nil, err
return nil, nil, false, err
}

// use the current client config
if ok {
clientConfig, err := loadRESTClientConfig(kubeconfigPath)
if err != nil {
return nil, nil, fmt.Errorf("unable to load kubeconfig: %v", err)
return nil, nil, false, fmt.Errorf("unable to load kubeconfig: %v", err)
}
klog.V(2).InfoS("Current kubeconfig file contents are still valid, no bootstrap necessary")
return clientConfig, restclient.CopyConfig(clientConfig), nil
return clientConfig, restclient.CopyConfig(clientConfig), false, nil
}

bootstrapClientConfig, err := loadRESTClientConfig(bootstrapPath)
if err != nil {
return nil, nil, fmt.Errorf("unable to load bootstrap kubeconfig: %v", err)
return nil, nil, true, fmt.Errorf("unable to load bootstrap kubeconfig: %v", err)
}

clientConfig := restclient.AnonymousClientConfig(bootstrapClientConfig)
pemPath := store.CurrentPath()
clientConfig.KeyFile = pemPath
clientConfig.CertFile = pemPath
if err := writeKubeconfigFromBootstrapping(clientConfig, kubeconfigPath, pemPath); err != nil {
return nil, nil, err
return nil, nil, true, err
}
klog.V(2).InfoS("Use the bootstrap credentials to request a cert, and set kubeconfig to point to the certificate dir")
return bootstrapClientConfig, clientConfig, nil
return bootstrapClientConfig, clientConfig, true, nil
}

// LoadClientCert requests a client cert for kubelet if the kubeconfigPath file does not exist.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ type Manager interface {
// be very conservative and only return true if recent communication has
// occurred with the server.
ServerHealthy() bool
// Returns true if it changed the cert, false otherwise. Error is only returned in
// exceptional cases.
RotateCerts() (bool, error)
}

// Config is the set of configuration parameters available for a new Manager.
Expand Down Expand Up @@ -429,10 +432,10 @@ func (m *manager) getClientset() (clientset.Interface, error) {
return m.clientsetFn(current)
}

// RotateCerts is exposed for testing only and is not a part of the public interface.
// Returns true if it changed the cert, false otherwise. Error is only returned in
// exceptional cases.
func (m *manager) RotateCerts() (bool, error) {
if m.forceRotation {
m.forceRotation = false
}
return m.rotateCerts()
}

Expand Down