kubelet: add key encipherment usage only if it is rsa key

remove allowOmittingUsageKeyEncipherment as it is always true

Signed-off-by: Paco Xu <paco.xu@daocloud.io>
This commit is contained in:
Paco Xu
2022-08-03 16:41:09 +08:00
parent 3ace3eb74b
commit 160f015ef4
9 changed files with 155 additions and 132 deletions

View File

@@ -62,10 +62,10 @@ var (
)
)
func IsKubeletServingCSR(req *x509.CertificateRequest, usages sets.String, allowOmittingUsageKeyEncipherment bool) bool {
return ValidateKubeletServingCSR(req, usages, allowOmittingUsageKeyEncipherment) == nil
func IsKubeletServingCSR(req *x509.CertificateRequest, usages sets.String) bool {
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) {
return organizationNotSystemNodesErr
}
@@ -82,14 +82,8 @@ func ValidateKubeletServingCSR(req *x509.CertificateRequest, usages sets.String,
return uriSANNotAllowedErr
}
if allowOmittingUsageKeyEncipherment {
if !kubeletServingRequiredUsages.Equal(usages) && !kubeletServingRequiredUsagesNoRSA.Equal(usages) {
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 !kubeletServingRequiredUsages.Equal(usages) && !kubeletServingRequiredUsagesNoRSA.Equal(usages) {
return fmt.Errorf("usages did not match %v", kubeletServingRequiredUsages.List())
}
if !strings.HasPrefix(req.Subject.CommonName, "system:node:") {
@@ -111,10 +105,10 @@ var (
)
)
func IsKubeletClientCSR(req *x509.CertificateRequest, usages sets.String, allowOmittingUsageKeyEncipherment bool) bool {
return ValidateKubeletClientCSR(req, usages, allowOmittingUsageKeyEncipherment) == nil
func IsKubeletClientCSR(req *x509.CertificateRequest, usages sets.String) bool {
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) {
return organizationNotSystemNodesErr
}
@@ -136,14 +130,8 @@ func ValidateKubeletClientCSR(req *x509.CertificateRequest, usages sets.String,
return commonNameNotSystemNode
}
if allowOmittingUsageKeyEncipherment {
if !kubeletClientRequiredUsages.Equal(usages) && !kubeletClientRequiredUsagesNoRSA.Equal(usages) {
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())
}
if !kubeletClientRequiredUsages.Equal(usages) && !kubeletClientRequiredUsagesNoRSA.Equal(usages) {
return fmt.Errorf("usages did not match %v", kubeletClientRequiredUsages.List())
}
return nil

View File

@@ -56,27 +56,27 @@ func DefaultSignerNameFromSpec(obj *certificatesv1beta1.CertificateSigningReques
// Set the signerName to 'legacy-unknown' as the CSR could not be
// recognised.
return certificatesv1beta1.LegacyUnknownSignerName
case IsKubeletClientCSR(csr, obj.Usages, true):
case IsKubeletClientCSR(csr, obj.Usages):
return certificatesv1beta1.KubeAPIServerClientKubeletSignerName
case IsKubeletServingCSR(csr, obj.Usages, true):
case IsKubeletServingCSR(csr, obj.Usages):
return certificatesv1beta1.KubeletServingSignerName
default:
return certificatesv1beta1.LegacyUnknownSignerName
}
}
func IsKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage, allowOmittingUsageKeyEncipherment bool) bool {
return certificates.IsKubeletServingCSR(req, usagesToSet(usages), allowOmittingUsageKeyEncipherment)
func IsKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) bool {
return certificates.IsKubeletServingCSR(req, usagesToSet(usages))
}
func ValidateKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage, allowOmittingUsageKeyEncipherment bool) error {
return certificates.ValidateKubeletServingCSR(req, usagesToSet(usages), allowOmittingUsageKeyEncipherment)
func ValidateKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) error {
return certificates.ValidateKubeletServingCSR(req, usagesToSet(usages))
}
func IsKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage, allowOmittingUsageKeyEncipherment bool) bool {
return certificates.IsKubeletClientCSR(req, usagesToSet(usages), allowOmittingUsageKeyEncipherment)
func IsKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) bool {
return certificates.IsKubeletClientCSR(req, usagesToSet(usages))
}
func ValidateKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage, allowOmittingUsageKeyEncipherment bool) error {
return certificates.ValidateKubeletClientCSR(req, usagesToSet(usages), allowOmittingUsageKeyEncipherment)
func ValidateKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) error {
return certificates.ValidateKubeletClientCSR(req, usagesToSet(usages))
}
func usagesToSet(usages []certificatesv1beta1.KeyUsage) sets.String {

View File

@@ -40,27 +40,19 @@ func TestIsKubeletServingCSR(t *testing.T) {
return csr
}
tests := map[string]struct {
req *x509.CertificateRequest
usages []capi.KeyUsage
allowOmittingUsageKeyEncipherment bool
exp bool
req *x509.CertificateRequest
usages []capi.KeyUsage
exp bool
}{
"defaults for kubelet-serving": {
req: newCSR(kubeletServerPEMOptions),
usages: kubeletServerUsages,
exp: true,
},
"defaults without key encipherment for kubelet-serving if allow omitting key encipherment": {
req: newCSR(kubeletServerPEMOptions),
usages: kubeletServerUsagesNoRSA,
allowOmittingUsageKeyEncipherment: true,
exp: true,
},
"defaults for kubelet-serving if allow omitting key encipherment": {
req: newCSR(kubeletServerPEMOptions),
usages: kubeletServerUsages,
allowOmittingUsageKeyEncipherment: true,
exp: true,
"defaults without key encipherment for kubelet-serving": {
req: newCSR(kubeletServerPEMOptions),
usages: kubeletServerUsagesNoRSA,
exp: true,
},
"does not default to kube-apiserver-client-kubelet if org is not 'system:nodes'": {
req: newCSR(kubeletServerPEMOptions, pemOptions{org: "not-system:nodes"}),
@@ -82,17 +74,6 @@ func TestIsKubeletServingCSR(t *testing.T) {
usages: kubeletServerUsages[1:],
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": {
req: newCSR(kubeletServerPEMOptions, pemOptions{ipAddresses: []net.IP{}, dnsNames: []string{}}),
usages: kubeletServerUsages[1:],
@@ -111,7 +92,7 @@ func TestIsKubeletServingCSR(t *testing.T) {
}
for name, test := range tests {
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 {
t.Errorf("unexpected IsKubeletClientCSR output: exp=%v, got=%v", test.exp, got)
}
@@ -129,10 +110,9 @@ func TestIsKubeletClientCSR(t *testing.T) {
return csr
}
tests := map[string]struct {
req *x509.CertificateRequest
usages []capi.KeyUsage
allowOmittingUsageKeyEncipherment bool
exp bool
req *x509.CertificateRequest
usages []capi.KeyUsage
exp bool
}{
"defaults for kube-apiserver-client-kubelet": {
req: newCSR(kubeletClientPEMOptions),
@@ -180,27 +160,19 @@ func TestIsKubeletClientCSR(t *testing.T) {
exp: false,
},
"does not default to kube-apiserver-client-kubelet if it is missing an expected usage without key encipherment": {
req: newCSR(kubeletClientPEMOptions),
usages: kubeletClientUsagesNoRSA[1:],
allowOmittingUsageKeyEncipherment: true,
exp: false,
},
"default to kube-apiserver-client-kubelet with key encipherment": {
req: newCSR(kubeletClientPEMOptions),
usages: kubeletClientUsages,
allowOmittingUsageKeyEncipherment: true,
exp: true,
req: newCSR(kubeletClientPEMOptions),
usages: kubeletClientUsagesNoRSA[1:],
exp: false,
},
"default to kube-apiserver-client-kubelet without key encipherment": {
req: newCSR(kubeletClientPEMOptions),
usages: kubeletClientUsagesNoRSA,
allowOmittingUsageKeyEncipherment: true,
exp: true,
req: newCSR(kubeletClientPEMOptions),
usages: kubeletClientUsagesNoRSA,
exp: true,
},
}
for name, test := range tests {
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 {
t.Errorf("unexpected IsKubeletClientCSR output: exp=%v, got=%v", test.exp, got)
}

View File

@@ -152,7 +152,7 @@ func isNodeClientCert(csr *capi.CertificateSigningRequest, x509cr *x509.Certific
if csr.Spec.SignerName != capi.KubeAPIServerClientKubeletSignerName {
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 {

View File

@@ -248,14 +248,14 @@ func isKubeletServing(req *x509.CertificateRequest, usages []capi.KeyUsage, sign
if signerName != capi.KubeletServingSignerName {
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) {
if signerName != capi.KubeAPIServerClientKubeletSignerName {
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) {

View File

@@ -19,6 +19,7 @@ package bootstrap
import (
"context"
"crypto"
"crypto/rsa"
"crypto/sha512"
"crypto/x509"
"crypto/x509/pkix"
@@ -329,9 +330,11 @@ func requestNodeCertificate(ctx context.Context, client clientset.Interface, pri
usages := []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
certificatesv1.UsageKeyEncipherment,
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.
signer, ok := privateKey.(crypto.Signer)

View File

@@ -105,23 +105,10 @@ func NewKubeletServerCertificateManager(kubeClient clientset.Interface, kubeCfg
}
m, err := certificate.NewManager(&certificate.Config{
ClientsetFn: clientsetFn,
GetTemplate: getTemplate,
SignerName: certificates.KubeletServingSignerName,
Usages: []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,
},
ClientsetFn: clientsetFn,
GetTemplate: getTemplate,
SignerName: certificates.KubeletServingSignerName,
GetUsages: certificate.DefaultKubeletServingGetUsages,
CertificateStore: certificateStore,
CertificateRotation: certificateRotationAge,
CertificateRenewFailure: certificateRenewFailure,
@@ -230,22 +217,7 @@ func NewKubeletClientCertificateManager(
},
},
SignerName: certificates.KubeAPIServerClientKubeletSignerName,
Usages: []certificates.KeyUsage{
// 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,
},
GetUsages: certificate.DefaultKubeletClientGetUsages,
// For backwards compatibility, the kubelet supports the ability to
// provide a higher privileged certificate as initial data that will
// then be rotated immediately. This code path is used by kubeadm on