mirror of
https://github.com/kubernetes/client-go.git
synced 2025-07-16 16:21:11 +00:00
Merge pull request #111660 from pacoxu/key-encipherment-v1.26
Key encipherment usage v1.27 Kubernetes-commit: 492637878f0b26fa126f2025af2ee5c1f1fd5867
This commit is contained in:
commit
37a1df5cba
@ -21,9 +21,11 @@ import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
@ -32,7 +34,7 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
certificates "k8s.io/api/certificates/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
@ -42,9 +44,76 @@ import (
|
||||
"k8s.io/client-go/util/keyutil"
|
||||
)
|
||||
|
||||
// certificateWaitTimeout controls the amount of time we wait for certificate
|
||||
// approval in one iteration.
|
||||
var certificateWaitTimeout = 15 * time.Minute
|
||||
var (
|
||||
// certificateWaitTimeout controls the amount of time we wait for certificate
|
||||
// approval in one iteration.
|
||||
certificateWaitTimeout = 15 * time.Minute
|
||||
|
||||
kubeletServingUsagesWithEncipherment = []certificates.KeyUsage{
|
||||
// https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||
//
|
||||
// Digital signature allows the certificate to be used to verify
|
||||
// digital signatures used during TLS negotiation.
|
||||
certificates.UsageDigitalSignature,
|
||||
// KeyEncipherment allows the cert/key pair to be used to encrypt
|
||||
// keys, including the symmetric keys negotiated during TLS setup
|
||||
// and used for data transfer.
|
||||
certificates.UsageKeyEncipherment,
|
||||
// ServerAuth allows the cert to be used by a TLS server to
|
||||
// authenticate itself to a TLS client.
|
||||
certificates.UsageServerAuth,
|
||||
}
|
||||
kubeletServingUsagesNoEncipherment = []certificates.KeyUsage{
|
||||
// https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||
//
|
||||
// Digital signature allows the certificate to be used to verify
|
||||
// digital signatures used during TLS negotiation.
|
||||
certificates.UsageDigitalSignature,
|
||||
// ServerAuth allows the cert to be used by a TLS server to
|
||||
// authenticate itself to a TLS client.
|
||||
certificates.UsageServerAuth,
|
||||
}
|
||||
DefaultKubeletServingGetUsages = func(privateKey interface{}) []certificates.KeyUsage {
|
||||
switch privateKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return kubeletServingUsagesWithEncipherment
|
||||
default:
|
||||
return kubeletServingUsagesNoEncipherment
|
||||
}
|
||||
}
|
||||
kubeletClientUsagesWithEncipherment = []certificates.KeyUsage{
|
||||
// https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||
//
|
||||
// Digital signature allows the certificate to be used to verify
|
||||
// digital signatures used during TLS negotiation.
|
||||
certificates.UsageDigitalSignature,
|
||||
// KeyEncipherment allows the cert/key pair to be used to encrypt
|
||||
// keys, including the symmetric keys negotiated during TLS setup
|
||||
// and used for data transfer.
|
||||
certificates.UsageKeyEncipherment,
|
||||
// ClientAuth allows the cert to be used by a TLS client to
|
||||
// authenticate itself to the TLS server.
|
||||
certificates.UsageClientAuth,
|
||||
}
|
||||
kubeletClientUsagesNoEncipherment = []certificates.KeyUsage{
|
||||
// https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||
//
|
||||
// Digital signature allows the certificate to be used to verify
|
||||
// digital signatures used during TLS negotiation.
|
||||
certificates.UsageDigitalSignature,
|
||||
// ClientAuth allows the cert to be used by a TLS client to
|
||||
// authenticate itself to the TLS server.
|
||||
certificates.UsageClientAuth,
|
||||
}
|
||||
DefaultKubeletClientGetUsages = func(privateKey interface{}) []certificates.KeyUsage {
|
||||
switch privateKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return kubeletClientUsagesWithEncipherment
|
||||
default:
|
||||
return kubeletClientUsagesNoEncipherment
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// Manager maintains and updates the certificates in use by this certificate
|
||||
// manager. In the background it communicates with the API server to get new
|
||||
@ -94,8 +163,12 @@ type Config struct {
|
||||
// the issued certificate is not guaranteed as the signer may choose to ignore the request.
|
||||
RequestedCertificateLifetime *time.Duration
|
||||
// Usages is the types of usages that certificates generated by the manager
|
||||
// can be used for.
|
||||
// can be used for. It is mutually exclusive with GetUsages.
|
||||
Usages []certificates.KeyUsage
|
||||
// GetUsages is dynamic way to get the types of usages that certificates generated by the manager
|
||||
// can be used for. If Usages is not nil, GetUsages has to be nil, vice versa.
|
||||
// It is mutually exclusive with Usages.
|
||||
GetUsages func(privateKey interface{}) []certificates.KeyUsage
|
||||
// CertificateStore is a persistent store where the current cert/key is
|
||||
// kept and future cert/key pairs will be persisted after they are
|
||||
// generated.
|
||||
@ -192,7 +265,7 @@ type manager struct {
|
||||
dynamicTemplate bool
|
||||
signerName string
|
||||
requestedCertificateLifetime *time.Duration
|
||||
usages []certificates.KeyUsage
|
||||
getUsages func(privateKey interface{}) []certificates.KeyUsage
|
||||
forceRotation bool
|
||||
|
||||
certStore Store
|
||||
@ -235,6 +308,18 @@ func NewManager(config *Config) (Manager, error) {
|
||||
getTemplate = func() *x509.CertificateRequest { return config.Template }
|
||||
}
|
||||
|
||||
if config.GetUsages != nil && config.Usages != nil {
|
||||
return nil, errors.New("cannot specify both GetUsages and Usages")
|
||||
}
|
||||
if config.GetUsages == nil && config.Usages == nil {
|
||||
return nil, errors.New("either GetUsages or Usages should be specified")
|
||||
}
|
||||
var getUsages func(interface{}) []certificates.KeyUsage
|
||||
if config.GetUsages != nil {
|
||||
getUsages = config.GetUsages
|
||||
} else {
|
||||
getUsages = func(interface{}) []certificates.KeyUsage { return config.Usages }
|
||||
}
|
||||
m := manager{
|
||||
stopCh: make(chan struct{}),
|
||||
clientsetFn: config.ClientsetFn,
|
||||
@ -242,7 +327,7 @@ func NewManager(config *Config) (Manager, error) {
|
||||
dynamicTemplate: config.GetTemplate != nil,
|
||||
signerName: config.SignerName,
|
||||
requestedCertificateLifetime: config.RequestedCertificateLifetime,
|
||||
usages: config.Usages,
|
||||
getUsages: getUsages,
|
||||
certStore: config.CertificateStore,
|
||||
cert: cert,
|
||||
forceRotation: forceRotation,
|
||||
@ -256,8 +341,9 @@ func NewManager(config *Config) (Manager, error) {
|
||||
name = m.signerName
|
||||
}
|
||||
if len(name) == 0 {
|
||||
usages := getUsages(nil)
|
||||
switch {
|
||||
case hasKeyUsage(config.Usages, certificates.UsageClientAuth):
|
||||
case hasKeyUsage(usages, certificates.UsageClientAuth):
|
||||
name = string(certificates.UsageClientAuth)
|
||||
default:
|
||||
name = "certificate"
|
||||
@ -416,7 +502,7 @@ func getCurrentCertificateOrBootstrap(
|
||||
bootstrapCert.Leaf = certs[0]
|
||||
|
||||
if _, err := store.Update(bootstrapCertificatePEM, bootstrapKeyPEM); err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("Unable to set the cert/key pair to the bootstrap certificate: %v", err))
|
||||
utilruntime.HandleError(fmt.Errorf("unable to set the cert/key pair to the bootstrap certificate: %v", err))
|
||||
}
|
||||
|
||||
return &bootstrapCert, true, nil
|
||||
@ -464,9 +550,14 @@ func (m *manager) rotateCerts() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
getUsages := m.getUsages
|
||||
if m.getUsages == nil {
|
||||
getUsages = DefaultKubeletClientGetUsages
|
||||
}
|
||||
usages := getUsages(privateKey)
|
||||
// Call the Certificate Signing Request API to get a certificate for the
|
||||
// new private key.
|
||||
reqName, reqUID, err := csr.RequestCertificate(clientSet, csrPEM, "", m.signerName, m.requestedCertificateLifetime, m.usages, privateKey)
|
||||
// new private key
|
||||
reqName, reqUID, err := csr.RequestCertificate(clientSet, csrPEM, "", m.signerName, m.requestedCertificateLifetime, usages, privateKey)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("%s: Failed while requesting a signed certificate from the control plane: %v", m.name, err))
|
||||
if m.certificateRenewFailure != nil {
|
||||
@ -622,17 +713,17 @@ func (m *manager) updateServerError(err error) error {
|
||||
m.certAccessLock.Lock()
|
||||
defer m.certAccessLock.Unlock()
|
||||
switch {
|
||||
case errors.IsUnauthorized(err):
|
||||
case apierrors.IsUnauthorized(err):
|
||||
// SSL terminating proxies may report this error instead of the master
|
||||
m.serverHealth = true
|
||||
case errors.IsUnexpectedServerError(err):
|
||||
case apierrors.IsUnexpectedServerError(err):
|
||||
// generally indicates a proxy or other load balancer problem, rather than a problem coming
|
||||
// from the master
|
||||
m.serverHealth = false
|
||||
default:
|
||||
// Identify known errors that could be expected for a cert request that
|
||||
// indicate everything is working normally
|
||||
m.serverHealth = errors.IsNotFound(err) || errors.IsForbidden(err)
|
||||
m.serverHealth = apierrors.IsNotFound(err) || apierrors.IsForbidden(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -276,7 +276,6 @@ func TestSetRotationDeadline(t *testing.T) {
|
||||
},
|
||||
},
|
||||
getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
|
||||
usages: []certificatesv1.KeyUsage{},
|
||||
now: func() time.Time { return now },
|
||||
logf: t.Logf,
|
||||
}
|
||||
@ -472,7 +471,6 @@ func TestRotateCertCreateCSRError(t *testing.T) {
|
||||
},
|
||||
},
|
||||
getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
|
||||
usages: []certificatesv1.KeyUsage{},
|
||||
clientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) {
|
||||
return newClientset(fakeClient{failureType: createError}), nil
|
||||
},
|
||||
@ -497,7 +495,6 @@ func TestRotateCertWaitingForResultError(t *testing.T) {
|
||||
},
|
||||
},
|
||||
getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
|
||||
usages: []certificatesv1.KeyUsage{},
|
||||
clientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) {
|
||||
return newClientset(fakeClient{failureType: watchError}), nil
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user