mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
Merge pull request #111660 from pacoxu/key-encipherment-v1.26
Key encipherment usage v1.27
This commit is contained in:
commit
492637878f
@ -62,10 +62,10 @@ var (
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
func IsKubeletServingCSR(req *x509.CertificateRequest, usages sets.String, allowOmittingUsageKeyEncipherment bool) bool {
|
func IsKubeletServingCSR(req *x509.CertificateRequest, usages sets.String) bool {
|
||||||
return ValidateKubeletServingCSR(req, usages, allowOmittingUsageKeyEncipherment) == nil
|
return ValidateKubeletServingCSR(req, usages) == nil
|
||||||
}
|
}
|
||||||
func ValidateKubeletServingCSR(req *x509.CertificateRequest, usages sets.String, allowOmittingUsageKeyEncipherment bool) error {
|
func ValidateKubeletServingCSR(req *x509.CertificateRequest, usages sets.String) error {
|
||||||
if !reflect.DeepEqual([]string{"system:nodes"}, req.Subject.Organization) {
|
if !reflect.DeepEqual([]string{"system:nodes"}, req.Subject.Organization) {
|
||||||
return organizationNotSystemNodesErr
|
return organizationNotSystemNodesErr
|
||||||
}
|
}
|
||||||
@ -82,15 +82,9 @@ func ValidateKubeletServingCSR(req *x509.CertificateRequest, usages sets.String,
|
|||||||
return uriSANNotAllowedErr
|
return uriSANNotAllowedErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if allowOmittingUsageKeyEncipherment {
|
|
||||||
if !kubeletServingRequiredUsages.Equal(usages) && !kubeletServingRequiredUsagesNoRSA.Equal(usages) {
|
if !kubeletServingRequiredUsages.Equal(usages) && !kubeletServingRequiredUsagesNoRSA.Equal(usages) {
|
||||||
return fmt.Errorf("usages did not match %v", kubeletServingRequiredUsages.List())
|
return fmt.Errorf("usages did not match %v", kubeletServingRequiredUsages.List())
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if !kubeletServingRequiredUsages.Equal(usages) {
|
|
||||||
return fmt.Errorf("usages did not match %v", kubeletServingRequiredUsages.List())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasPrefix(req.Subject.CommonName, "system:node:") {
|
if !strings.HasPrefix(req.Subject.CommonName, "system:node:") {
|
||||||
return commonNameNotSystemNode
|
return commonNameNotSystemNode
|
||||||
@ -111,10 +105,10 @@ var (
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
func IsKubeletClientCSR(req *x509.CertificateRequest, usages sets.String, allowOmittingUsageKeyEncipherment bool) bool {
|
func IsKubeletClientCSR(req *x509.CertificateRequest, usages sets.String) bool {
|
||||||
return ValidateKubeletClientCSR(req, usages, allowOmittingUsageKeyEncipherment) == nil
|
return ValidateKubeletClientCSR(req, usages) == nil
|
||||||
}
|
}
|
||||||
func ValidateKubeletClientCSR(req *x509.CertificateRequest, usages sets.String, allowOmittingUsageKeyEncipherment bool) error {
|
func ValidateKubeletClientCSR(req *x509.CertificateRequest, usages sets.String) error {
|
||||||
if !reflect.DeepEqual([]string{"system:nodes"}, req.Subject.Organization) {
|
if !reflect.DeepEqual([]string{"system:nodes"}, req.Subject.Organization) {
|
||||||
return organizationNotSystemNodesErr
|
return organizationNotSystemNodesErr
|
||||||
}
|
}
|
||||||
@ -136,15 +130,9 @@ func ValidateKubeletClientCSR(req *x509.CertificateRequest, usages sets.String,
|
|||||||
return commonNameNotSystemNode
|
return commonNameNotSystemNode
|
||||||
}
|
}
|
||||||
|
|
||||||
if allowOmittingUsageKeyEncipherment {
|
|
||||||
if !kubeletClientRequiredUsages.Equal(usages) && !kubeletClientRequiredUsagesNoRSA.Equal(usages) {
|
if !kubeletClientRequiredUsages.Equal(usages) && !kubeletClientRequiredUsagesNoRSA.Equal(usages) {
|
||||||
return fmt.Errorf("usages did not match %v", kubeletClientRequiredUsages.List())
|
return fmt.Errorf("usages did not match %v", kubeletClientRequiredUsages.List())
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if !kubeletClientRequiredUsages.Equal(usages) {
|
|
||||||
return fmt.Errorf("usages did not match %v", kubeletClientRequiredUsages.List())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -56,27 +56,27 @@ func DefaultSignerNameFromSpec(obj *certificatesv1beta1.CertificateSigningReques
|
|||||||
// Set the signerName to 'legacy-unknown' as the CSR could not be
|
// Set the signerName to 'legacy-unknown' as the CSR could not be
|
||||||
// recognised.
|
// recognised.
|
||||||
return certificatesv1beta1.LegacyUnknownSignerName
|
return certificatesv1beta1.LegacyUnknownSignerName
|
||||||
case IsKubeletClientCSR(csr, obj.Usages, false):
|
case IsKubeletClientCSR(csr, obj.Usages):
|
||||||
return certificatesv1beta1.KubeAPIServerClientKubeletSignerName
|
return certificatesv1beta1.KubeAPIServerClientKubeletSignerName
|
||||||
case IsKubeletServingCSR(csr, obj.Usages, false):
|
case IsKubeletServingCSR(csr, obj.Usages):
|
||||||
return certificatesv1beta1.KubeletServingSignerName
|
return certificatesv1beta1.KubeletServingSignerName
|
||||||
default:
|
default:
|
||||||
return certificatesv1beta1.LegacyUnknownSignerName
|
return certificatesv1beta1.LegacyUnknownSignerName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage, allowOmittingUsageKeyEncipherment bool) bool {
|
func IsKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) bool {
|
||||||
return certificates.IsKubeletServingCSR(req, usagesToSet(usages), allowOmittingUsageKeyEncipherment)
|
return certificates.IsKubeletServingCSR(req, usagesToSet(usages))
|
||||||
}
|
}
|
||||||
func ValidateKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage, allowOmittingUsageKeyEncipherment bool) error {
|
func ValidateKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) error {
|
||||||
return certificates.ValidateKubeletServingCSR(req, usagesToSet(usages), allowOmittingUsageKeyEncipherment)
|
return certificates.ValidateKubeletServingCSR(req, usagesToSet(usages))
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage, allowOmittingUsageKeyEncipherment bool) bool {
|
func IsKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) bool {
|
||||||
return certificates.IsKubeletClientCSR(req, usagesToSet(usages), allowOmittingUsageKeyEncipherment)
|
return certificates.IsKubeletClientCSR(req, usagesToSet(usages))
|
||||||
}
|
}
|
||||||
func ValidateKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage, allowOmittingUsageKeyEncipherment bool) error {
|
func ValidateKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) error {
|
||||||
return certificates.ValidateKubeletClientCSR(req, usagesToSet(usages), allowOmittingUsageKeyEncipherment)
|
return certificates.ValidateKubeletClientCSR(req, usagesToSet(usages))
|
||||||
}
|
}
|
||||||
|
|
||||||
func usagesToSet(usages []certificatesv1beta1.KeyUsage) sets.String {
|
func usagesToSet(usages []certificatesv1beta1.KeyUsage) sets.String {
|
||||||
|
@ -42,7 +42,6 @@ func TestIsKubeletServingCSR(t *testing.T) {
|
|||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
req *x509.CertificateRequest
|
req *x509.CertificateRequest
|
||||||
usages []capi.KeyUsage
|
usages []capi.KeyUsage
|
||||||
allowOmittingUsageKeyEncipherment bool
|
|
||||||
exp bool
|
exp bool
|
||||||
}{
|
}{
|
||||||
"defaults for kubelet-serving": {
|
"defaults for kubelet-serving": {
|
||||||
@ -50,16 +49,9 @@ func TestIsKubeletServingCSR(t *testing.T) {
|
|||||||
usages: kubeletServerUsages,
|
usages: kubeletServerUsages,
|
||||||
exp: true,
|
exp: true,
|
||||||
},
|
},
|
||||||
"defaults without key encipherment for kubelet-serving if allow omitting key encipherment": {
|
"defaults without key encipherment for kubelet-serving": {
|
||||||
req: newCSR(kubeletServerPEMOptions),
|
req: newCSR(kubeletServerPEMOptions),
|
||||||
usages: kubeletServerUsagesNoRSA,
|
usages: kubeletServerUsagesNoRSA,
|
||||||
allowOmittingUsageKeyEncipherment: true,
|
|
||||||
exp: true,
|
|
||||||
},
|
|
||||||
"defaults for kubelet-serving if allow omitting key encipherment": {
|
|
||||||
req: newCSR(kubeletServerPEMOptions),
|
|
||||||
usages: kubeletServerUsages,
|
|
||||||
allowOmittingUsageKeyEncipherment: true,
|
|
||||||
exp: true,
|
exp: true,
|
||||||
},
|
},
|
||||||
"does not default to kube-apiserver-client-kubelet if org is not 'system:nodes'": {
|
"does not default to kube-apiserver-client-kubelet if org is not 'system:nodes'": {
|
||||||
@ -82,17 +74,6 @@ func TestIsKubeletServingCSR(t *testing.T) {
|
|||||||
usages: kubeletServerUsages[1:],
|
usages: kubeletServerUsages[1:],
|
||||||
exp: false,
|
exp: false,
|
||||||
},
|
},
|
||||||
"does not default to kubelet-serving if it is missing an expected usage if allow omitting key encipherment": {
|
|
||||||
req: newCSR(kubeletServerPEMOptions),
|
|
||||||
usages: kubeletServerUsagesNoRSA[1:],
|
|
||||||
allowOmittingUsageKeyEncipherment: true,
|
|
||||||
exp: false,
|
|
||||||
},
|
|
||||||
"does not default to kubelet-serving if it is missing an expected usage withou key encipherment": {
|
|
||||||
req: newCSR(kubeletServerPEMOptions),
|
|
||||||
usages: kubeletServerUsagesNoRSA,
|
|
||||||
exp: false,
|
|
||||||
},
|
|
||||||
"does not default to kubelet-serving if it does not specify any dnsNames or ipAddresses": {
|
"does not default to kubelet-serving if it does not specify any dnsNames or ipAddresses": {
|
||||||
req: newCSR(kubeletServerPEMOptions, pemOptions{ipAddresses: []net.IP{}, dnsNames: []string{}}),
|
req: newCSR(kubeletServerPEMOptions, pemOptions{ipAddresses: []net.IP{}, dnsNames: []string{}}),
|
||||||
usages: kubeletServerUsages[1:],
|
usages: kubeletServerUsages[1:],
|
||||||
@ -111,7 +92,7 @@ func TestIsKubeletServingCSR(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
got := IsKubeletServingCSR(test.req, test.usages, test.allowOmittingUsageKeyEncipherment)
|
got := IsKubeletServingCSR(test.req, test.usages)
|
||||||
if test.exp != got {
|
if test.exp != got {
|
||||||
t.Errorf("unexpected IsKubeletClientCSR output: exp=%v, got=%v", test.exp, got)
|
t.Errorf("unexpected IsKubeletClientCSR output: exp=%v, got=%v", test.exp, got)
|
||||||
}
|
}
|
||||||
@ -131,7 +112,6 @@ func TestIsKubeletClientCSR(t *testing.T) {
|
|||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
req *x509.CertificateRequest
|
req *x509.CertificateRequest
|
||||||
usages []capi.KeyUsage
|
usages []capi.KeyUsage
|
||||||
allowOmittingUsageKeyEncipherment bool
|
|
||||||
exp bool
|
exp bool
|
||||||
}{
|
}{
|
||||||
"defaults for kube-apiserver-client-kubelet": {
|
"defaults for kube-apiserver-client-kubelet": {
|
||||||
@ -182,25 +162,17 @@ func TestIsKubeletClientCSR(t *testing.T) {
|
|||||||
"does not default to kube-apiserver-client-kubelet if it is missing an expected usage without key encipherment": {
|
"does not default to kube-apiserver-client-kubelet if it is missing an expected usage without key encipherment": {
|
||||||
req: newCSR(kubeletClientPEMOptions),
|
req: newCSR(kubeletClientPEMOptions),
|
||||||
usages: kubeletClientUsagesNoRSA[1:],
|
usages: kubeletClientUsagesNoRSA[1:],
|
||||||
allowOmittingUsageKeyEncipherment: true,
|
|
||||||
exp: false,
|
exp: false,
|
||||||
},
|
},
|
||||||
"default to kube-apiserver-client-kubelet with key encipherment": {
|
|
||||||
req: newCSR(kubeletClientPEMOptions),
|
|
||||||
usages: kubeletClientUsages,
|
|
||||||
allowOmittingUsageKeyEncipherment: true,
|
|
||||||
exp: true,
|
|
||||||
},
|
|
||||||
"default to kube-apiserver-client-kubelet without key encipherment": {
|
"default to kube-apiserver-client-kubelet without key encipherment": {
|
||||||
req: newCSR(kubeletClientPEMOptions),
|
req: newCSR(kubeletClientPEMOptions),
|
||||||
usages: kubeletClientUsagesNoRSA,
|
usages: kubeletClientUsagesNoRSA,
|
||||||
allowOmittingUsageKeyEncipherment: true,
|
|
||||||
exp: true,
|
exp: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
got := IsKubeletClientCSR(test.req, test.usages, test.allowOmittingUsageKeyEncipherment)
|
got := IsKubeletClientCSR(test.req, test.usages)
|
||||||
if test.exp != got {
|
if test.exp != got {
|
||||||
t.Errorf("unexpected IsKubeletClientCSR output: exp=%v, got=%v", test.exp, got)
|
t.Errorf("unexpected IsKubeletClientCSR output: exp=%v, got=%v", test.exp, got)
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ func isNodeClientCert(csr *capi.CertificateSigningRequest, x509cr *x509.Certific
|
|||||||
if csr.Spec.SignerName != capi.KubeAPIServerClientKubeletSignerName {
|
if csr.Spec.SignerName != capi.KubeAPIServerClientKubeletSignerName {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return capihelper.IsKubeletClientCSR(x509cr, usagesToSet(csr.Spec.Usages), true)
|
return capihelper.IsKubeletClientCSR(x509cr, usagesToSet(csr.Spec.Usages))
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSelfNodeClientCert(csr *capi.CertificateSigningRequest, x509cr *x509.CertificateRequest) bool {
|
func isSelfNodeClientCert(csr *capi.CertificateSigningRequest, x509cr *x509.CertificateRequest) bool {
|
||||||
|
@ -248,14 +248,14 @@ func isKubeletServing(req *x509.CertificateRequest, usages []capi.KeyUsage, sign
|
|||||||
if signerName != capi.KubeletServingSignerName {
|
if signerName != capi.KubeletServingSignerName {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
return true, capihelper.ValidateKubeletServingCSR(req, usagesToSet(usages), true)
|
return true, capihelper.ValidateKubeletServingCSR(req, usagesToSet(usages))
|
||||||
}
|
}
|
||||||
|
|
||||||
func isKubeletClient(req *x509.CertificateRequest, usages []capi.KeyUsage, signerName string) (bool, error) {
|
func isKubeletClient(req *x509.CertificateRequest, usages []capi.KeyUsage, signerName string) (bool, error) {
|
||||||
if signerName != capi.KubeAPIServerClientKubeletSignerName {
|
if signerName != capi.KubeAPIServerClientKubeletSignerName {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
return true, capihelper.ValidateKubeletClientCSR(req, usagesToSet(usages), true)
|
return true, capihelper.ValidateKubeletClientCSR(req, usagesToSet(usages))
|
||||||
}
|
}
|
||||||
|
|
||||||
func isKubeAPIServerClient(req *x509.CertificateRequest, usages []capi.KeyUsage, signerName string) (bool, error) {
|
func isKubeAPIServerClient(req *x509.CertificateRequest, usages []capi.KeyUsage, signerName string) (bool, error) {
|
||||||
|
@ -19,6 +19,7 @@ package bootstrap
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
|
"crypto/rsa"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
@ -329,9 +330,11 @@ func requestNodeCertificate(ctx context.Context, client clientset.Interface, pri
|
|||||||
|
|
||||||
usages := []certificatesv1.KeyUsage{
|
usages := []certificatesv1.KeyUsage{
|
||||||
certificatesv1.UsageDigitalSignature,
|
certificatesv1.UsageDigitalSignature,
|
||||||
certificatesv1.UsageKeyEncipherment,
|
|
||||||
certificatesv1.UsageClientAuth,
|
certificatesv1.UsageClientAuth,
|
||||||
}
|
}
|
||||||
|
if _, ok := privateKey.(*rsa.PrivateKey); ok {
|
||||||
|
usages = append(usages, certificatesv1.UsageKeyEncipherment)
|
||||||
|
}
|
||||||
|
|
||||||
// The Signer interface contains the Public() method to get the public key.
|
// The Signer interface contains the Public() method to get the public key.
|
||||||
signer, ok := privateKey.(crypto.Signer)
|
signer, ok := privateKey.(crypto.Signer)
|
||||||
|
@ -108,20 +108,7 @@ func NewKubeletServerCertificateManager(kubeClient clientset.Interface, kubeCfg
|
|||||||
ClientsetFn: clientsetFn,
|
ClientsetFn: clientsetFn,
|
||||||
GetTemplate: getTemplate,
|
GetTemplate: getTemplate,
|
||||||
SignerName: certificates.KubeletServingSignerName,
|
SignerName: certificates.KubeletServingSignerName,
|
||||||
Usages: []certificates.KeyUsage{
|
GetUsages: certificate.DefaultKubeletServingGetUsages,
|
||||||
// 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,
|
|
||||||
},
|
|
||||||
CertificateStore: certificateStore,
|
CertificateStore: certificateStore,
|
||||||
CertificateRotation: certificateRotationAge,
|
CertificateRotation: certificateRotationAge,
|
||||||
CertificateRenewFailure: certificateRenewFailure,
|
CertificateRenewFailure: certificateRenewFailure,
|
||||||
@ -230,22 +217,7 @@ func NewKubeletClientCertificateManager(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
SignerName: certificates.KubeAPIServerClientKubeletSignerName,
|
SignerName: certificates.KubeAPIServerClientKubeletSignerName,
|
||||||
Usages: []certificates.KeyUsage{
|
GetUsages: certificate.DefaultKubeletClientGetUsages,
|
||||||
// https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
|
||||||
//
|
|
||||||
// DigitalSignature allows the certificate to be used to verify
|
|
||||||
// digital signatures including 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,
|
|
||||||
},
|
|
||||||
|
|
||||||
// For backwards compatibility, the kubelet supports the ability to
|
// For backwards compatibility, the kubelet supports the ability to
|
||||||
// provide a higher privileged certificate as initial data that will
|
// provide a higher privileged certificate as initial data that will
|
||||||
// then be rotated immediately. This code path is used by kubeadm on
|
// then be rotated immediately. This code path is used by kubeadm on
|
||||||
|
@ -21,9 +21,11 @@ import (
|
|||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
cryptorand "crypto/rand"
|
cryptorand "crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
@ -32,7 +34,7 @@ import (
|
|||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
certificates "k8s.io/api/certificates/v1"
|
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"
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
@ -42,9 +44,76 @@ import (
|
|||||||
"k8s.io/client-go/util/keyutil"
|
"k8s.io/client-go/util/keyutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// certificateWaitTimeout controls the amount of time we wait for certificate
|
var (
|
||||||
// approval in one iteration.
|
// certificateWaitTimeout controls the amount of time we wait for certificate
|
||||||
var certificateWaitTimeout = 15 * time.Minute
|
// 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 maintains and updates the certificates in use by this certificate
|
||||||
// manager. In the background it communicates with the API server to get new
|
// 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.
|
// the issued certificate is not guaranteed as the signer may choose to ignore the request.
|
||||||
RequestedCertificateLifetime *time.Duration
|
RequestedCertificateLifetime *time.Duration
|
||||||
// Usages is the types of usages that certificates generated by the manager
|
// 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
|
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
|
// CertificateStore is a persistent store where the current cert/key is
|
||||||
// kept and future cert/key pairs will be persisted after they are
|
// kept and future cert/key pairs will be persisted after they are
|
||||||
// generated.
|
// generated.
|
||||||
@ -192,7 +265,7 @@ type manager struct {
|
|||||||
dynamicTemplate bool
|
dynamicTemplate bool
|
||||||
signerName string
|
signerName string
|
||||||
requestedCertificateLifetime *time.Duration
|
requestedCertificateLifetime *time.Duration
|
||||||
usages []certificates.KeyUsage
|
getUsages func(privateKey interface{}) []certificates.KeyUsage
|
||||||
forceRotation bool
|
forceRotation bool
|
||||||
|
|
||||||
certStore Store
|
certStore Store
|
||||||
@ -235,6 +308,18 @@ func NewManager(config *Config) (Manager, error) {
|
|||||||
getTemplate = func() *x509.CertificateRequest { return config.Template }
|
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{
|
m := manager{
|
||||||
stopCh: make(chan struct{}),
|
stopCh: make(chan struct{}),
|
||||||
clientsetFn: config.ClientsetFn,
|
clientsetFn: config.ClientsetFn,
|
||||||
@ -242,7 +327,7 @@ func NewManager(config *Config) (Manager, error) {
|
|||||||
dynamicTemplate: config.GetTemplate != nil,
|
dynamicTemplate: config.GetTemplate != nil,
|
||||||
signerName: config.SignerName,
|
signerName: config.SignerName,
|
||||||
requestedCertificateLifetime: config.RequestedCertificateLifetime,
|
requestedCertificateLifetime: config.RequestedCertificateLifetime,
|
||||||
usages: config.Usages,
|
getUsages: getUsages,
|
||||||
certStore: config.CertificateStore,
|
certStore: config.CertificateStore,
|
||||||
cert: cert,
|
cert: cert,
|
||||||
forceRotation: forceRotation,
|
forceRotation: forceRotation,
|
||||||
@ -256,8 +341,9 @@ func NewManager(config *Config) (Manager, error) {
|
|||||||
name = m.signerName
|
name = m.signerName
|
||||||
}
|
}
|
||||||
if len(name) == 0 {
|
if len(name) == 0 {
|
||||||
|
usages := getUsages(nil)
|
||||||
switch {
|
switch {
|
||||||
case hasKeyUsage(config.Usages, certificates.UsageClientAuth):
|
case hasKeyUsage(usages, certificates.UsageClientAuth):
|
||||||
name = string(certificates.UsageClientAuth)
|
name = string(certificates.UsageClientAuth)
|
||||||
default:
|
default:
|
||||||
name = "certificate"
|
name = "certificate"
|
||||||
@ -416,7 +502,7 @@ func getCurrentCertificateOrBootstrap(
|
|||||||
bootstrapCert.Leaf = certs[0]
|
bootstrapCert.Leaf = certs[0]
|
||||||
|
|
||||||
if _, err := store.Update(bootstrapCertificatePEM, bootstrapKeyPEM); err != nil {
|
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
|
return &bootstrapCert, true, nil
|
||||||
@ -464,9 +550,14 @@ func (m *manager) rotateCerts() (bool, error) {
|
|||||||
return false, nil
|
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
|
// Call the Certificate Signing Request API to get a certificate for the
|
||||||
// new private key.
|
// new private key
|
||||||
reqName, reqUID, err := csr.RequestCertificate(clientSet, csrPEM, "", m.signerName, m.requestedCertificateLifetime, m.usages, privateKey)
|
reqName, reqUID, err := csr.RequestCertificate(clientSet, csrPEM, "", m.signerName, m.requestedCertificateLifetime, usages, privateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utilruntime.HandleError(fmt.Errorf("%s: Failed while requesting a signed certificate from the control plane: %v", m.name, err))
|
utilruntime.HandleError(fmt.Errorf("%s: Failed while requesting a signed certificate from the control plane: %v", m.name, err))
|
||||||
if m.certificateRenewFailure != nil {
|
if m.certificateRenewFailure != nil {
|
||||||
@ -622,17 +713,17 @@ func (m *manager) updateServerError(err error) error {
|
|||||||
m.certAccessLock.Lock()
|
m.certAccessLock.Lock()
|
||||||
defer m.certAccessLock.Unlock()
|
defer m.certAccessLock.Unlock()
|
||||||
switch {
|
switch {
|
||||||
case errors.IsUnauthorized(err):
|
case apierrors.IsUnauthorized(err):
|
||||||
// SSL terminating proxies may report this error instead of the master
|
// SSL terminating proxies may report this error instead of the master
|
||||||
m.serverHealth = true
|
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
|
// generally indicates a proxy or other load balancer problem, rather than a problem coming
|
||||||
// from the master
|
// from the master
|
||||||
m.serverHealth = false
|
m.serverHealth = false
|
||||||
default:
|
default:
|
||||||
// Identify known errors that could be expected for a cert request that
|
// Identify known errors that could be expected for a cert request that
|
||||||
// indicate everything is working normally
|
// indicate everything is working normally
|
||||||
m.serverHealth = errors.IsNotFound(err) || errors.IsForbidden(err)
|
m.serverHealth = apierrors.IsNotFound(err) || apierrors.IsForbidden(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -276,7 +276,6 @@ func TestSetRotationDeadline(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
|
getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
|
||||||
usages: []certificatesv1.KeyUsage{},
|
|
||||||
now: func() time.Time { return now },
|
now: func() time.Time { return now },
|
||||||
logf: t.Logf,
|
logf: t.Logf,
|
||||||
}
|
}
|
||||||
@ -472,7 +471,6 @@ func TestRotateCertCreateCSRError(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
|
getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
|
||||||
usages: []certificatesv1.KeyUsage{},
|
|
||||||
clientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) {
|
clientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) {
|
||||||
return newClientset(fakeClient{failureType: createError}), nil
|
return newClientset(fakeClient{failureType: createError}), nil
|
||||||
},
|
},
|
||||||
@ -497,7 +495,6 @@ func TestRotateCertWaitingForResultError(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
|
getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
|
||||||
usages: []certificatesv1.KeyUsage{},
|
|
||||||
clientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) {
|
clientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) {
|
||||||
return newClientset(fakeClient{failureType: watchError}), nil
|
return newClientset(fakeClient{failureType: watchError}), nil
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user