Skip to content

Commit

Permalink
kubeadm: enhance certs check-expiration to show the expiration info o…
Browse files Browse the repository at this point in the history
…f related CAs
  • Loading branch information
SataQiu committed Oct 16, 2019
1 parent 63bd1d7 commit 68f7c2a
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 14 deletions.
22 changes: 20 additions & 2 deletions cmd/kubeadm/app/cmd/alpha/certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,27 @@ func newCmdCertsExpiration(out io.Writer, kdir string) *cobra.Command {
return "no"
}
w := tabwriter.NewWriter(out, 10, 4, 3, ' ', 0)
fmt.Fprintln(w, "CERTIFICATE\tEXPIRES\tRESIDUAL TIME\tEXTERNALLY MANAGED")
fmt.Fprintln(w, "CERTIFICATE\tEXPIRES\tRESIDUAL TIME\tCERTIFICATE AUTHORITY\tEXTERNALLY MANAGED")
for _, handler := range rm.Certificates() {
e, err := rm.GetExpirationInfo(handler.Name)
e, err := rm.GetCertificateExpirationInfo(handler.Name)
if err != nil {
return err
}

s := fmt.Sprintf("%s\t%s\t%s\t%s\t%-8v",
e.Name,
e.ExpirationDate.Format("Jan 02, 2006 15:04 MST"),
duration.ShortHumanDuration(e.ResidualTime()),
handler.CAName,
yesNo(e.ExternallyManaged),
)

fmt.Fprintln(w, s)
}
fmt.Fprintln(w)
fmt.Fprintln(w, "CERTIFICATE AUTHORITY\tEXPIRES\tRESIDUAL TIME\tEXTERNALLY MANAGED")
for _, handler := range rm.CAs() {
e, err := rm.GetCAExpirationInfo(handler.Name)
if err != nil {
return err
}
Expand Down
91 changes: 79 additions & 12 deletions cmd/kubeadm/app/phases/certs/renewal/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ type Manager struct {

// certificates contains the certificateRenewHandler controlled by this manager
certificates map[string]*CertificateRenewHandler

// cas contains the CAExpirationHandler related to the certificates that are controlled by this manager
cas map[string]*CAExpirationHandler
}

// CertificateRenewHandler defines required info for renewing a certificate
Expand All @@ -54,10 +57,29 @@ type CertificateRenewHandler struct {
// FileName defines the name (or the BaseName) of the certificate file
FileName string

// CABaseName define the base name for the CA that should be used for certificate renewal
// CAName defines the name for the CA on which this certificate depends
CAName string

// CABaseName defines the base name for the CA that should be used for certificate renewal
CABaseName string

// readwriter define a CertificateReadWriter to be used for certificate renewal
// readwriter defines a CertificateReadWriter to be used for certificate renewal
readwriter certificateReadWriter
}

// CAExpirationHandler defines required info for CA expiration check
type CAExpirationHandler struct {
// Name of the CA to be used for UX.
// This value can be used to trigger operations on this CA
Name string

// LongName of the CA to be used for UX
LongName string

// FileName defines the name (or the BaseName) of the CA file
FileName string

// readwriter defines a CertificateReadWriter to be used for CA expiration check
readwriter certificateReadWriter
}

Expand All @@ -67,6 +89,7 @@ func NewManager(cfg *kubeadmapi.ClusterConfiguration, kubernetesDir string) (*Ma
cfg: cfg,
kubernetesDir: kubernetesDir,
certificates: map[string]*CertificateRenewHandler{},
cas: map[string]*CAExpirationHandler{},
}

// gets the list of certificates that are expected according to the current cluster configuration
Expand All @@ -93,10 +116,19 @@ func NewManager(cfg *kubeadmapi.ClusterConfiguration, kubernetesDir string) (*Ma
Name: cert.Name,
LongName: cert.LongName,
FileName: cert.BaseName,
CAName: ca.Name,
CABaseName: ca.BaseName, //Nb. this is a path for etcd certs (they are stored in a subfolder)
readwriter: pkiReadWriter,
}
}

pkiReadWriter := newPKICertificateReadWriter(rm.cfg.CertificatesDir, ca.BaseName)
rm.cas[ca.Name] = &CAExpirationHandler{
Name: ca.Name,
LongName: ca.LongName,
FileName: ca.BaseName,
readwriter: pkiReadWriter,
}
}

// gets the list of certificates that should be considered for renewal
Expand Down Expand Up @@ -139,7 +171,7 @@ func NewManager(cfg *kubeadmapi.ClusterConfiguration, kubernetesDir string) (*Ma
return rm, nil
}

// Certificates return the list of certificates controlled by this Manager
// Certificates returns the list of certificates controlled by this Manager
func (rm *Manager) Certificates() []*CertificateRenewHandler {
certificates := []*CertificateRenewHandler{}
for _, h := range rm.certificates {
Expand All @@ -151,6 +183,18 @@ func (rm *Manager) Certificates() []*CertificateRenewHandler {
return certificates
}

// CAs returns the list of CAs related to the certificates that are controlled by this manager
func (rm *Manager) CAs() []*CAExpirationHandler {
cas := []*CAExpirationHandler{}
for _, h := range rm.cas {
cas = append(cas, h)
}

sort.Slice(cas, func(i, j int) bool { return cas[i].Name < cas[j].Name })

return cas
}

// RenewUsingLocalCA executes certificate renewal using local certificate authorities for generating new certs.
// For PKI certificates, use the name defined in the certsphase package, while for certificates
// embedded in the kubeConfig files, use the kubeConfig file name defined in the kubeadm constants package.
Expand All @@ -162,7 +206,7 @@ func (rm *Manager) RenewUsingLocalCA(name string) (bool, error) {
}

// checks if the certificate is externally managed (CA certificate provided without the certificate key)
externallyManaged, err := rm.IsExternallyManaged(handler)
externallyManaged, err := rm.IsExternallyManaged(handler.CABaseName)
if err != nil {
return false, err
}
Expand Down Expand Up @@ -271,18 +315,18 @@ func (rm *Manager) CreateRenewCSR(name, outdir string) error {
return nil
}

// GetExpirationInfo returns certificate expiration info.
// GetCertificateExpirationInfo returns certificate expiration info.
// For PKI certificates, use the name defined in the certsphase package, while for certificates
// embedded in the kubeConfig files, use the kubeConfig file name defined in the kubeadm constants package.
// If you use the CertificateRenewHandler returned by Certificates func, handler.Name already contains the right value.
func (rm *Manager) GetExpirationInfo(name string) (*ExpirationInfo, error) {
func (rm *Manager) GetCertificateExpirationInfo(name string) (*ExpirationInfo, error) {
handler, ok := rm.certificates[name]
if !ok {
return nil, errors.Errorf("%s is not a known certificate", name)
}

// checks if the certificate is externally managed (CA certificate provided without the certificate key)
externallyManaged, err := rm.IsExternallyManaged(handler)
externallyManaged, err := rm.IsExternallyManaged(handler.CABaseName)
if err != nil {
return nil, err
}
Expand All @@ -297,25 +341,48 @@ func (rm *Manager) GetExpirationInfo(name string) (*ExpirationInfo, error) {
return newExpirationInfo(name, cert, externallyManaged), nil
}

// GetCAExpirationInfo returns CA expiration info.
func (rm *Manager) GetCAExpirationInfo(name string) (*ExpirationInfo, error) {
handler, ok := rm.cas[name]
if !ok {
return nil, errors.Errorf("%s is not a known CA", name)
}

// checks if the CA is externally managed (CA certificate provided without the certificate key)
externallyManaged, err := rm.IsExternallyManaged(handler.FileName)
if err != nil {
return nil, err
}

// reads the current CA
ca, err := handler.readwriter.Read()
if err != nil {
return nil, err
}

// returns the CA expiration info
return newExpirationInfo(name, ca, externallyManaged), nil
}

// IsExternallyManaged checks if we are in the external CA case (CA certificate provided without the certificate key)
func (rm *Manager) IsExternallyManaged(h *CertificateRenewHandler) (bool, error) {
switch h.CABaseName {
func (rm *Manager) IsExternallyManaged(caBaseName string) (bool, error) {
switch caBaseName {
case kubeadmconstants.CACertAndKeyBaseName:
externallyManaged, err := certsphase.UsingExternalCA(rm.cfg)
if err != nil {
return false, errors.Wrapf(err, "Error checking external CA condition for %s certificate authority", h.CABaseName)
return false, errors.Wrapf(err, "Error checking external CA condition for %s certificate authority", caBaseName)
}
return externallyManaged, nil
case kubeadmconstants.FrontProxyCACertAndKeyBaseName:
externallyManaged, err := certsphase.UsingExternalFrontProxyCA(rm.cfg)
if err != nil {
return false, errors.Wrapf(err, "Error checking external CA condition for %s certificate authority", h.CABaseName)
return false, errors.Wrapf(err, "Error checking external CA condition for %s certificate authority", caBaseName)
}
return externallyManaged, nil
case kubeadmconstants.EtcdCACertAndKeyBaseName:
return false, nil
default:
return false, errors.Errorf("unknown certificate authority %s", h.CABaseName)
return false, errors.Errorf("unknown certificate authority %s", caBaseName)
}
}

Expand Down

0 comments on commit 68f7c2a

Please sign in to comment.