diff --git a/cmd/kube-controller-manager/app/certificates.go b/cmd/kube-controller-manager/app/certificates.go index b1cae432505..69b9cf42a14 100644 --- a/cmd/kube-controller-manager/app/certificates.go +++ b/cmd/kube-controller-manager/app/certificates.go @@ -89,7 +89,7 @@ func startCSRSigningController(ctx ControllerContext) (http.Handler, bool, error } c := ctx.ClientBuilder.ClientOrDie("certificate-controller") - csrInformer := ctx.InformerFactory.Certificates().V1beta1().CertificateSigningRequests() + csrInformer := ctx.InformerFactory.Certificates().V1().CertificateSigningRequests() certTTL := ctx.ComponentConfig.CSRSigningController.ClusterSigningDuration.Duration caFile, caKeyFile := getKubeletServingSignerFiles(ctx.ComponentConfig.CSRSigningController) @@ -137,7 +137,7 @@ func startCSRApprovingController(ctx ControllerContext) (http.Handler, bool, err approver := approver.NewCSRApprovingController( ctx.ClientBuilder.ClientOrDie("certificate-controller"), - ctx.InformerFactory.Certificates().V1beta1().CertificateSigningRequests(), + ctx.InformerFactory.Certificates().V1().CertificateSigningRequests(), ) go approver.Run(1, ctx.Stop) @@ -146,8 +146,8 @@ func startCSRApprovingController(ctx ControllerContext) (http.Handler, bool, err func startCSRCleanerController(ctx ControllerContext) (http.Handler, bool, error) { cleaner := cleaner.NewCSRCleanerController( - ctx.ClientBuilder.ClientOrDie("certificate-controller").CertificatesV1beta1().CertificateSigningRequests(), - ctx.InformerFactory.Certificates().V1beta1().CertificateSigningRequests(), + ctx.ClientBuilder.ClientOrDie("certificate-controller").CertificatesV1().CertificateSigningRequests(), + ctx.InformerFactory.Certificates().V1().CertificateSigningRequests(), ) go cleaner.Run(1, ctx.Stop) return nil, true, nil diff --git a/pkg/apis/certificates/BUILD b/pkg/apis/certificates/BUILD index 9c7dabb45ee..095b0363790 100644 --- a/pkg/apis/certificates/BUILD +++ b/pkg/apis/certificates/BUILD @@ -20,6 +20,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", ], ) diff --git a/pkg/apis/certificates/helpers.go b/pkg/apis/certificates/helpers.go index 2608e407626..ef88bf8a527 100644 --- a/pkg/apis/certificates/helpers.go +++ b/pkg/apis/certificates/helpers.go @@ -20,12 +20,15 @@ import ( "crypto/x509" "encoding/pem" "errors" + "fmt" + "reflect" + "strings" + + "k8s.io/apimachinery/pkg/util/sets" ) -// ParseCSR extracts the CSR from the API object and decodes it. -func ParseCSR(obj *CertificateSigningRequest) (*x509.CertificateRequest, error) { - // extract PEM from request object - pemBytes := obj.Spec.Request +// ParseCSR extracts the CSR from the bytes and decodes it. +func ParseCSR(pemBytes []byte) (*x509.CertificateRequest, error) { block, _ := pem.Decode(pemBytes) if block == nil || block.Type != "CERTIFICATE REQUEST" { return nil, errors.New("PEM block type must be CERTIFICATE REQUEST") @@ -36,3 +39,88 @@ func ParseCSR(obj *CertificateSigningRequest) (*x509.CertificateRequest, error) } return csr, nil } + +var ( + organizationNotSystemNodesErr = fmt.Errorf("subject organization is not system:nodes") + commonNameNotSystemNode = fmt.Errorf("subject common name does not begin with system:node:") + dnsOrIPSANRequiredErr = fmt.Errorf("DNS or IP subjectAltName is required") + dnsSANNotAllowedErr = fmt.Errorf("DNS subjectAltNames are not allowed") + emailSANNotAllowedErr = fmt.Errorf("Email subjectAltNames are not allowed") + ipSANNotAllowedErr = fmt.Errorf("IP subjectAltNames are not allowed") + uriSANNotAllowedErr = fmt.Errorf("URI subjectAltNames are not allowed") +) + +var kubeletServingRequiredUsages = sets.NewString( + string(UsageDigitalSignature), + string(UsageKeyEncipherment), + string(UsageServerAuth), +) + +func IsKubeletServingCSR(req *x509.CertificateRequest, usages sets.String) bool { + return ValidateKubeletServingCSR(req, usages) == nil +} +func ValidateKubeletServingCSR(req *x509.CertificateRequest, usages sets.String) error { + if !reflect.DeepEqual([]string{"system:nodes"}, req.Subject.Organization) { + return organizationNotSystemNodesErr + } + + // at least one of dnsNames or ipAddresses must be specified + if len(req.DNSNames) == 0 && len(req.IPAddresses) == 0 { + return dnsOrIPSANRequiredErr + } + + if len(req.EmailAddresses) > 0 { + return emailSANNotAllowedErr + } + if len(req.URIs) > 0 { + return uriSANNotAllowedErr + } + + if !kubeletServingRequiredUsages.Equal(usages) { + return fmt.Errorf("usages did not match %v", kubeletServingRequiredUsages.List()) + } + + if !strings.HasPrefix(req.Subject.CommonName, "system:node:") { + return commonNameNotSystemNode + } + + return nil +} + +var kubeletClientRequiredUsages = sets.NewString( + string(UsageDigitalSignature), + string(UsageKeyEncipherment), + string(UsageClientAuth), +) + +func IsKubeletClientCSR(req *x509.CertificateRequest, usages sets.String) bool { + return ValidateKubeletClientCSR(req, usages) == nil +} +func ValidateKubeletClientCSR(req *x509.CertificateRequest, usages sets.String) error { + if !reflect.DeepEqual([]string{"system:nodes"}, req.Subject.Organization) { + return organizationNotSystemNodesErr + } + + if len(req.DNSNames) > 0 { + return dnsSANNotAllowedErr + } + if len(req.EmailAddresses) > 0 { + return emailSANNotAllowedErr + } + if len(req.IPAddresses) > 0 { + return ipSANNotAllowedErr + } + if len(req.URIs) > 0 { + return uriSANNotAllowedErr + } + + if !strings.HasPrefix(req.Subject.CommonName, "system:node:") { + return commonNameNotSystemNode + } + + if !kubeletClientRequiredUsages.Equal(usages) { + return fmt.Errorf("usages did not match %v", kubeletClientRequiredUsages.List()) + } + + return nil +} diff --git a/pkg/apis/certificates/v1beta1/defaults.go b/pkg/apis/certificates/v1beta1/defaults.go index 83a43876b43..14133d9df2a 100644 --- a/pkg/apis/certificates/v1beta1/defaults.go +++ b/pkg/apis/certificates/v1beta1/defaults.go @@ -18,14 +18,12 @@ package v1beta1 import ( "crypto/x509" - "fmt" - "reflect" - "strings" certificatesv1beta1 "k8s.io/api/certificates/v1beta1" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/sets" + certificates "k8s.io/kubernetes/pkg/apis/certificates" ) func addDefaultingFuncs(scheme *runtime.Scheme) error { @@ -67,99 +65,24 @@ func DefaultSignerNameFromSpec(obj *certificatesv1beta1.CertificateSigningReques } } -var ( - organizationNotSystemNodesErr = fmt.Errorf("subject organization is not system:nodes") - commonNameNotSystemNode = fmt.Errorf("subject common name does not begin with system:node:") - dnsOrIPSANRequiredErr = fmt.Errorf("DNS or IP subjectAltName is required") - dnsSANNotAllowedErr = fmt.Errorf("DNS subjectAltNames are not allowed") - emailSANNotAllowedErr = fmt.Errorf("Email subjectAltNames are not allowed") - ipSANNotAllowedErr = fmt.Errorf("IP subjectAltNames are not allowed") - uriSANNotAllowedErr = fmt.Errorf("URI subjectAltNames are not allowed") -) - func IsKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) bool { - return ValidateKubeletServingCSR(req, usages) == nil + return certificates.IsKubeletServingCSR(req, usagesToSet(usages)) } func ValidateKubeletServingCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) error { - if !reflect.DeepEqual([]string{"system:nodes"}, req.Subject.Organization) { - return organizationNotSystemNodesErr - } - - // at least one of dnsNames or ipAddresses must be specified - if len(req.DNSNames) == 0 && len(req.IPAddresses) == 0 { - return dnsOrIPSANRequiredErr - } - - if len(req.EmailAddresses) > 0 { - return emailSANNotAllowedErr - } - if len(req.URIs) > 0 { - return uriSANNotAllowedErr - } - - requiredUsages := []certificatesv1beta1.KeyUsage{ - certificatesv1beta1.UsageDigitalSignature, - certificatesv1beta1.UsageKeyEncipherment, - certificatesv1beta1.UsageServerAuth, - } - if !equalUnsorted(requiredUsages, usages) { - return fmt.Errorf("usages did not match %v", requiredUsages) - } - - if !strings.HasPrefix(req.Subject.CommonName, "system:node:") { - return commonNameNotSystemNode - } - - return nil + return certificates.ValidateKubeletServingCSR(req, usagesToSet(usages)) } func IsKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) bool { - return ValidateKubeletClientCSR(req, usages) == nil + return certificates.IsKubeletClientCSR(req, usagesToSet(usages)) } func ValidateKubeletClientCSR(req *x509.CertificateRequest, usages []certificatesv1beta1.KeyUsage) error { - if !reflect.DeepEqual([]string{"system:nodes"}, req.Subject.Organization) { - return organizationNotSystemNodesErr - } - - if len(req.DNSNames) > 0 { - return dnsSANNotAllowedErr - } - if len(req.EmailAddresses) > 0 { - return emailSANNotAllowedErr - } - if len(req.IPAddresses) > 0 { - return ipSANNotAllowedErr - } - if len(req.URIs) > 0 { - return uriSANNotAllowedErr - } - - if !strings.HasPrefix(req.Subject.CommonName, "system:node:") { - return commonNameNotSystemNode - } - - requiredUsages := []certificatesv1beta1.KeyUsage{ - certificatesv1beta1.UsageDigitalSignature, - certificatesv1beta1.UsageKeyEncipherment, - certificatesv1beta1.UsageClientAuth, - } - if !equalUnsorted(requiredUsages, usages) { - return fmt.Errorf("usages did not match %v", requiredUsages) - } - - return nil + return certificates.ValidateKubeletClientCSR(req, usagesToSet(usages)) } -// equalUnsorted compares two []string for equality of contents regardless of -// the order of the elements -func equalUnsorted(left, right []certificatesv1beta1.KeyUsage) bool { - l := sets.NewString() - for _, s := range left { - l.Insert(string(s)) +func usagesToSet(usages []certificatesv1beta1.KeyUsage) sets.String { + result := sets.NewString() + for _, usage := range usages { + result.Insert(string(usage)) } - r := sets.NewString() - for _, s := range right { - r.Insert(string(s)) - } - return l.Equal(r) + return result } diff --git a/pkg/apis/certificates/validation/validation.go b/pkg/apis/certificates/validation/validation.go index ab64a9dfb3f..f182027e439 100644 --- a/pkg/apis/certificates/validation/validation.go +++ b/pkg/apis/certificates/validation/validation.go @@ -84,7 +84,7 @@ type certificateValidationOptions struct { // PEM-encoded PKCS#10 certificate signing request. If this is invalid, we must // not accept the CSR for further processing. func validateCSR(obj *certificates.CertificateSigningRequest) error { - csr, err := certificates.ParseCSR(obj) + csr, err := certificates.ParseCSR(obj.Spec.Request) if err != nil { return err } diff --git a/pkg/controller/certificates/BUILD b/pkg/controller/certificates/BUILD index 3e9133793a1..985f25b1190 100644 --- a/pkg/controller/certificates/BUILD +++ b/pkg/controller/certificates/BUILD @@ -13,17 +13,16 @@ go_library( importpath = "k8s.io/kubernetes/pkg/controller/certificates", visibility = ["//visibility:public"], deps = [ - "//pkg/apis/certificates/v1beta1:go_default_library", "//pkg/controller:go_default_library", - "//staging/src/k8s.io/api/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/api/certificates/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", - "//staging/src/k8s.io/client-go/informers/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/client-go/informers/certificates/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", - "//staging/src/k8s.io/client-go/listers/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/client-go/listers/certificates/v1:go_default_library", "//staging/src/k8s.io/client-go/tools/cache:go_default_library", "//staging/src/k8s.io/client-go/tools/record:go_default_library", "//staging/src/k8s.io/client-go/util/workqueue:go_default_library", @@ -64,7 +63,7 @@ go_test( embed = [":go_default_library"], deps = [ "//pkg/controller:go_default_library", - "//staging/src/k8s.io/api/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/api/certificates/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/client-go/informers:go_default_library", diff --git a/pkg/controller/certificates/approver/BUILD b/pkg/controller/certificates/approver/BUILD index 1516c2c7498..6b3b4d1a666 100644 --- a/pkg/controller/certificates/approver/BUILD +++ b/pkg/controller/certificates/approver/BUILD @@ -11,9 +11,9 @@ go_test( srcs = ["sarapprove_test.go"], embed = [":go_default_library"], deps = [ - "//pkg/apis/certificates/v1beta1:go_default_library", + "//pkg/apis/certificates/v1:go_default_library", "//staging/src/k8s.io/api/authorization/v1:go_default_library", - "//staging/src/k8s.io/api/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/api/certificates/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", @@ -26,12 +26,14 @@ go_library( srcs = ["sarapprove.go"], importpath = "k8s.io/kubernetes/pkg/controller/certificates/approver", deps = [ - "//pkg/apis/certificates/v1beta1:go_default_library", + "//pkg/apis/certificates:go_default_library", "//pkg/controller/certificates:go_default_library", "//staging/src/k8s.io/api/authorization/v1:go_default_library", - "//staging/src/k8s.io/api/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/api/certificates/v1:go_default_library", + "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//staging/src/k8s.io/client-go/informers/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", + "//staging/src/k8s.io/client-go/informers/certificates/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", ], ) diff --git a/pkg/controller/certificates/approver/sarapprove.go b/pkg/controller/certificates/approver/sarapprove.go index 7ab7aff1112..397a75f5689 100644 --- a/pkg/controller/certificates/approver/sarapprove.go +++ b/pkg/controller/certificates/approver/sarapprove.go @@ -23,12 +23,14 @@ import ( "fmt" authorization "k8s.io/api/authorization/v1" - capi "k8s.io/api/certificates/v1beta1" + capi "k8s.io/api/certificates/v1" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - certificatesinformers "k8s.io/client-go/informers/certificates/v1beta1" + "k8s.io/apimachinery/pkg/util/sets" + certificatesinformers "k8s.io/client-go/informers/certificates/v1" clientset "k8s.io/client-go/kubernetes" - capihelper "k8s.io/kubernetes/pkg/apis/certificates/v1beta1" + capihelper "k8s.io/kubernetes/pkg/apis/certificates" "k8s.io/kubernetes/pkg/controller/certificates" ) @@ -100,7 +102,7 @@ func (a *sarApprover) handle(csr *capi.CertificateSigningRequest) error { } if approved { appendApprovalCondition(csr, r.successMessage) - _, err = a.client.CertificatesV1beta1().CertificateSigningRequests().UpdateApproval(context.Background(), csr, metav1.UpdateOptions{}) + _, err = a.client.CertificatesV1().CertificateSigningRequests().UpdateApproval(context.Background(), csr.Name, csr, metav1.UpdateOptions{}) if err != nil { return fmt.Errorf("error updating approval for csr: %v", err) } @@ -140,25 +142,30 @@ func (a *sarApprover) authorize(csr *capi.CertificateSigningRequest, rattrs auth func appendApprovalCondition(csr *capi.CertificateSigningRequest, message string) { csr.Status.Conditions = append(csr.Status.Conditions, capi.CertificateSigningRequestCondition{ Type: capi.CertificateApproved, + Status: corev1.ConditionTrue, Reason: "AutoApproved", Message: message, }) } func isNodeClientCert(csr *capi.CertificateSigningRequest, x509cr *x509.CertificateRequest) bool { - isClientCSR := capihelper.IsKubeletClientCSR(x509cr, csr.Spec.Usages) - if !isClientCSR { + if csr.Spec.SignerName != capi.KubeAPIServerClientKubeletSignerName { return false } - return *csr.Spec.SignerName == capi.KubeAPIServerClientKubeletSignerName + return capihelper.IsKubeletClientCSR(x509cr, usagesToSet(csr.Spec.Usages)) } func isSelfNodeClientCert(csr *capi.CertificateSigningRequest, x509cr *x509.CertificateRequest) bool { - if !isNodeClientCert(csr, x509cr) { - return false - } if csr.Spec.Username != x509cr.Subject.CommonName { return false } - return true + return isNodeClientCert(csr, x509cr) +} + +func usagesToSet(usages []capi.KeyUsage) sets.String { + result := sets.NewString() + for _, usage := range usages { + result.Insert(string(usage)) + } + return result } diff --git a/pkg/controller/certificates/approver/sarapprove_test.go b/pkg/controller/certificates/approver/sarapprove_test.go index ee0afa11ee7..e3c02bc0923 100644 --- a/pkg/controller/certificates/approver/sarapprove_test.go +++ b/pkg/controller/certificates/approver/sarapprove_test.go @@ -28,12 +28,12 @@ import ( "testing" authorization "k8s.io/api/authorization/v1" - capi "k8s.io/api/certificates/v1beta1" + capi "k8s.io/api/certificates/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/kubernetes/fake" testclient "k8s.io/client-go/testing" - k8s_certificates_v1beta1 "k8s.io/kubernetes/pkg/apis/certificates/v1beta1" + k8s_certificates_v1 "k8s.io/kubernetes/pkg/apis/certificates/v1" ) func TestHandle(t *testing.T) { @@ -86,7 +86,7 @@ func TestHandle(t *testing.T) { if got, expected := a.Verb, "update"; got != expected { t.Errorf("got: %v, expected: %v", got, expected) } - if got, expected := a.Resource, (schema.GroupVersionResource{Group: "certificates.k8s.io", Version: "v1beta1", Resource: "certificatesigningrequests"}); got != expected { + if got, expected := a.Resource, (schema.GroupVersionResource{Group: "certificates.k8s.io", Version: "v1", Resource: "certificatesigningrequests"}); got != expected { t.Errorf("got: %v, expected: %v", got, expected) } if got, expected := a.Subresource, "approval"; got != expected { @@ -201,7 +201,7 @@ func testRecognizer(t *testing.T, cases []func(b *csrBuilder), recognizeFunc fun c(&b) t.Run(fmt.Sprintf("csr:%#v", b), func(t *testing.T) { csr := makeFancyTestCsr(b) - x509cr, err := k8s_certificates_v1beta1.ParseCSR(csr.Spec.Request) + x509cr, err := k8s_certificates_v1.ParseCSR(csr.Spec.Request) if err != nil { t.Errorf("unexpected err: %v", err) } @@ -252,7 +252,7 @@ func makeFancyTestCsr(b csrBuilder) *capi.CertificateSigningRequest { Spec: capi.CertificateSigningRequestSpec{ Username: b.requestor, Usages: b.usages, - SignerName: &b.signerName, + SignerName: b.signerName, Request: pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrb}), }, } diff --git a/pkg/controller/certificates/authority/BUILD b/pkg/controller/certificates/authority/BUILD index 7c109cc8f18..e8a4050a979 100644 --- a/pkg/controller/certificates/authority/BUILD +++ b/pkg/controller/certificates/authority/BUILD @@ -14,7 +14,7 @@ go_library( "//cmd/kubelet/app:__pkg__", "//pkg/controller/certificates:__subpackages__", ], - deps = ["//staging/src/k8s.io/api/certificates/v1beta1:go_default_library"], + deps = ["//staging/src/k8s.io/api/certificates/v1:go_default_library"], ) filegroup( @@ -39,7 +39,7 @@ go_test( ], embed = [":go_default_library"], deps = [ - "//staging/src/k8s.io/api/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/api/certificates/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library", "//vendor/github.com/google/go-cmp/cmp:go_default_library", "//vendor/github.com/google/go-cmp/cmp/cmpopts:go_default_library", diff --git a/pkg/controller/certificates/authority/authority_test.go b/pkg/controller/certificates/authority/authority_test.go index daf5698c3e8..a875e4f737f 100644 --- a/pkg/controller/certificates/authority/authority_test.go +++ b/pkg/controller/certificates/authority/authority_test.go @@ -30,7 +30,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - capi "k8s.io/api/certificates/v1beta1" + capi "k8s.io/api/certificates/v1" "k8s.io/apimachinery/pkg/util/diff" ) diff --git a/pkg/controller/certificates/authority/policies.go b/pkg/controller/certificates/authority/policies.go index 5c84e3ad005..0d8d9b374d1 100644 --- a/pkg/controller/certificates/authority/policies.go +++ b/pkg/controller/certificates/authority/policies.go @@ -22,7 +22,7 @@ import ( "sort" "time" - capi "k8s.io/api/certificates/v1beta1" + capi "k8s.io/api/certificates/v1" ) // SigningPolicy validates a CertificateRequest before it's signed by the diff --git a/pkg/controller/certificates/authority/policies_test.go b/pkg/controller/certificates/authority/policies_test.go index f7053dbfcdc..68db4cc27c1 100644 --- a/pkg/controller/certificates/authority/policies_test.go +++ b/pkg/controller/certificates/authority/policies_test.go @@ -22,7 +22,7 @@ import ( "reflect" "testing" - capi "k8s.io/api/certificates/v1beta1" + capi "k8s.io/api/certificates/v1" ) func TestKeyUsagesFromStrings(t *testing.T) { diff --git a/pkg/controller/certificates/certificate_controller.go b/pkg/controller/certificates/certificate_controller.go index e030a945407..086126395c3 100644 --- a/pkg/controller/certificates/certificate_controller.go +++ b/pkg/controller/certificates/certificate_controller.go @@ -24,19 +24,18 @@ import ( "golang.org/x/time/rate" - certificates "k8s.io/api/certificates/v1beta1" + certificates "k8s.io/api/certificates/v1" "k8s.io/apimachinery/pkg/api/errors" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" - certificatesinformers "k8s.io/client-go/informers/certificates/v1beta1" + certificatesinformers "k8s.io/client-go/informers/certificates/v1" clientset "k8s.io/client-go/kubernetes" v1core "k8s.io/client-go/kubernetes/typed/core/v1" - certificateslisters "k8s.io/client-go/listers/certificates/v1beta1" + certificateslisters "k8s.io/client-go/listers/certificates/v1" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" "k8s.io/client-go/util/workqueue" "k8s.io/klog/v2" - capihelper "k8s.io/kubernetes/pkg/apis/certificates/v1beta1" "k8s.io/kubernetes/pkg/controller" ) @@ -193,15 +192,6 @@ func (cc *CertificateController) syncFunc(key string) error { // need to operate on a copy so we don't mutate the csr in the shared cache csr = csr.DeepCopy() - // If the `signerName` field is not set, we are talking to a pre-1.18 apiserver. - // As per the KEP document for the certificates API, this will be defaulted here - // in the controller to maintain backwards compatibility. - // This should be removed after a deprecation window has passed. - // Default here to allow handlers to assume the field is set. - if csr.Spec.SignerName == nil { - signerName := capihelper.DefaultSignerNameFromSpec(&csr.Spec) - csr.Spec.SignerName = &signerName - } return cc.handler(csr) } diff --git a/pkg/controller/certificates/certificate_controller_test.go b/pkg/controller/certificates/certificate_controller_test.go index 7d3129d7193..e8be06e334f 100644 --- a/pkg/controller/certificates/certificate_controller_test.go +++ b/pkg/controller/certificates/certificate_controller_test.go @@ -21,7 +21,7 @@ import ( "testing" "time" - certificates "k8s.io/api/certificates/v1beta1" + certificates "k8s.io/api/certificates/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/informers" @@ -48,7 +48,7 @@ func TestCertificateController(t *testing.T) { Reason: "test reason", Message: "test message", }) - _, err := client.CertificatesV1beta1().CertificateSigningRequests().UpdateApproval(context.TODO(), csr, metav1.UpdateOptions{}) + _, err := client.CertificatesV1().CertificateSigningRequests().UpdateApproval(context.TODO(), csr.Name, csr, metav1.UpdateOptions{}) if err != nil { return err } @@ -58,7 +58,7 @@ func TestCertificateController(t *testing.T) { controller := NewCertificateController( "test", client, - informerFactory.Certificates().V1beta1().CertificateSigningRequests(), + informerFactory.Certificates().V1().CertificateSigningRequests(), handler, ) controller.csrsSynced = func() bool { return true } diff --git a/pkg/controller/certificates/certificate_controller_utils.go b/pkg/controller/certificates/certificate_controller_utils.go index 941a72dca23..91c84f6da1c 100644 --- a/pkg/controller/certificates/certificate_controller_utils.go +++ b/pkg/controller/certificates/certificate_controller_utils.go @@ -17,7 +17,7 @@ limitations under the License. package certificates import ( - certificates "k8s.io/api/certificates/v1beta1" + certificates "k8s.io/api/certificates/v1" v1 "k8s.io/api/core/v1" ) diff --git a/pkg/controller/certificates/certificate_controller_utils_test.go b/pkg/controller/certificates/certificate_controller_utils_test.go index d601db4db8e..bf31ddd725e 100644 --- a/pkg/controller/certificates/certificate_controller_utils_test.go +++ b/pkg/controller/certificates/certificate_controller_utils_test.go @@ -21,14 +21,14 @@ import ( "github.com/stretchr/testify/assert" - "k8s.io/api/certificates/v1beta1" + certificatesapi "k8s.io/api/certificates/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func TestIsCertificateRequestApproved(t *testing.T) { testCases := []struct { name string - conditions []v1beta1.CertificateSigningRequestCondition + conditions []certificatesapi.CertificateSigningRequestCondition expectedIsApproved bool }{ { @@ -37,28 +37,28 @@ func TestIsCertificateRequestApproved(t *testing.T) { false, }, { "Approved not exist and Denied exist", - []v1beta1.CertificateSigningRequestCondition{ + []certificatesapi.CertificateSigningRequestCondition{ { - Type: v1beta1.CertificateDenied, + Type: certificatesapi.CertificateDenied, }, }, false, }, { "Approved exist and Denied not exist", - []v1beta1.CertificateSigningRequestCondition{ + []certificatesapi.CertificateSigningRequestCondition{ { - Type: v1beta1.CertificateApproved, + Type: certificatesapi.CertificateApproved, }, }, true, }, { "Both of Approved and Denied exist", - []v1beta1.CertificateSigningRequestCondition{ + []certificatesapi.CertificateSigningRequestCondition{ { - Type: v1beta1.CertificateApproved, + Type: certificatesapi.CertificateApproved, }, { - Type: v1beta1.CertificateDenied, + Type: certificatesapi.CertificateDenied, }, }, false, @@ -66,11 +66,11 @@ func TestIsCertificateRequestApproved(t *testing.T) { } for _, tc := range testCases { - csr := &v1beta1.CertificateSigningRequest{ + csr := &certificatesapi.CertificateSigningRequest{ ObjectMeta: v1.ObjectMeta{ Name: "fake-csr", }, - Status: v1beta1.CertificateSigningRequestStatus{ + Status: certificatesapi.CertificateSigningRequestStatus{ Conditions: tc.conditions, }, } diff --git a/pkg/controller/certificates/cleaner/BUILD b/pkg/controller/certificates/cleaner/BUILD index b1a3ec1028e..ddbe08d5a09 100644 --- a/pkg/controller/certificates/cleaner/BUILD +++ b/pkg/controller/certificates/cleaner/BUILD @@ -6,14 +6,14 @@ go_library( importpath = "k8s.io/kubernetes/pkg/controller/certificates/cleaner", visibility = ["//visibility:public"], deps = [ - "//staging/src/k8s.io/api/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/api/certificates/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", - "//staging/src/k8s.io/client-go/informers/certificates/v1beta1:go_default_library", - "//staging/src/k8s.io/client-go/kubernetes/typed/certificates/v1beta1:go_default_library", - "//staging/src/k8s.io/client-go/listers/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/client-go/informers/certificates/v1:go_default_library", + "//staging/src/k8s.io/client-go/kubernetes/typed/certificates/v1:go_default_library", + "//staging/src/k8s.io/client-go/listers/certificates/v1:go_default_library", "//vendor/k8s.io/klog/v2:go_default_library", ], ) @@ -37,7 +37,7 @@ go_test( srcs = ["cleaner_test.go"], embed = [":go_default_library"], deps = [ - "//staging/src/k8s.io/api/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/api/certificates/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", ], diff --git a/pkg/controller/certificates/cleaner/cleaner.go b/pkg/controller/certificates/cleaner/cleaner.go index b62d5510743..832c678bfa2 100644 --- a/pkg/controller/certificates/cleaner/cleaner.go +++ b/pkg/controller/certificates/cleaner/cleaner.go @@ -29,14 +29,14 @@ import ( "k8s.io/klog/v2" - capi "k8s.io/api/certificates/v1beta1" + capi "k8s.io/api/certificates/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" - certificatesinformers "k8s.io/client-go/informers/certificates/v1beta1" - csrclient "k8s.io/client-go/kubernetes/typed/certificates/v1beta1" - certificateslisters "k8s.io/client-go/listers/certificates/v1beta1" + certificatesinformers "k8s.io/client-go/informers/certificates/v1" + csrclient "k8s.io/client-go/kubernetes/typed/certificates/v1" + certificateslisters "k8s.io/client-go/listers/certificates/v1" ) const ( diff --git a/pkg/controller/certificates/cleaner/cleaner_test.go b/pkg/controller/certificates/cleaner/cleaner_test.go index 4d9303d0c11..848c48cb058 100644 --- a/pkg/controller/certificates/cleaner/cleaner_test.go +++ b/pkg/controller/certificates/cleaner/cleaner_test.go @@ -20,7 +20,7 @@ import ( "testing" "time" - capi "k8s.io/api/certificates/v1beta1" + capi "k8s.io/api/certificates/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" ) @@ -211,7 +211,7 @@ func TestCleanerWithApprovedExpiredCSR(t *testing.T) { client := fake.NewSimpleClientset(csr) s := &CSRCleanerController{ - csrClient: client.CertificatesV1beta1().CertificateSigningRequests(), + csrClient: client.CertificatesV1().CertificateSigningRequests(), } err := s.handle(csr) diff --git a/pkg/controller/certificates/signer/BUILD b/pkg/controller/certificates/signer/BUILD index 46ca96560c4..6958607c6c7 100644 --- a/pkg/controller/certificates/signer/BUILD +++ b/pkg/controller/certificates/signer/BUILD @@ -16,9 +16,9 @@ go_test( ], embed = [":go_default_library"], deps = [ - "//pkg/apis/certificates/v1beta1:go_default_library", + "//pkg/apis/certificates/v1:go_default_library", "//pkg/controller/certificates:go_default_library", - "//staging/src/k8s.io/api/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/api/certificates/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/clock:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", @@ -36,14 +36,16 @@ go_library( ], importpath = "k8s.io/kubernetes/pkg/controller/certificates/signer", deps = [ - "//pkg/apis/certificates/v1beta1:go_default_library", + "//pkg/apis/certificates:go_default_library", "//pkg/controller/certificates:go_default_library", "//pkg/controller/certificates/authority:go_default_library", + "//staging/src/k8s.io/api/certificates/v1:go_default_library", "//staging/src/k8s.io/api/certificates/v1beta1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server/dynamiccertificates:go_default_library", - "//staging/src/k8s.io/client-go/informers/certificates/v1beta1:go_default_library", + "//staging/src/k8s.io/client-go/informers/certificates/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/util/cert:go_default_library", "//staging/src/k8s.io/client-go/util/keyutil:go_default_library", diff --git a/pkg/controller/certificates/signer/signer.go b/pkg/controller/certificates/signer/signer.go index 986a95f94c8..a6c084ef45c 100644 --- a/pkg/controller/certificates/signer/signer.go +++ b/pkg/controller/certificates/signer/signer.go @@ -24,13 +24,15 @@ import ( "fmt" "time" - capi "k8s.io/api/certificates/v1beta1" + capi "k8s.io/api/certificates/v1" + capiv1beta1 "k8s.io/api/certificates/v1beta1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/server/dynamiccertificates" - certificatesinformers "k8s.io/client-go/informers/certificates/v1beta1" + certificatesinformers "k8s.io/client-go/informers/certificates/v1" clientset "k8s.io/client-go/kubernetes" - capihelper "k8s.io/kubernetes/pkg/apis/certificates/v1beta1" + capihelper "k8s.io/kubernetes/pkg/apis/certificates" "k8s.io/kubernetes/pkg/controller/certificates" "k8s.io/kubernetes/pkg/controller/certificates/authority" ) @@ -73,7 +75,7 @@ func NewLegacyUnknownCSRSigningController( caFile, caKeyFile string, certTTL time.Duration, ) (*CSRSigningController, error) { - return NewCSRSigningController("csrsigning-legacy-unknown", capi.LegacyUnknownSignerName, client, csrInformer, caFile, caKeyFile, certTTL) + return NewCSRSigningController("csrsigning-legacy-unknown", capiv1beta1.LegacyUnknownSignerName, client, csrInformer, caFile, caKeyFile, certTTL) } func NewCSRSigningController( @@ -146,7 +148,7 @@ func (s *signer) handle(csr *capi.CertificateSigningRequest) error { } // Fast-path to avoid any additional processing if the CSRs signerName does not match - if *csr.Spec.SignerName != s.signerName { + if csr.Spec.SignerName != s.signerName { return nil } @@ -154,7 +156,7 @@ func (s *signer) handle(csr *capi.CertificateSigningRequest) error { if err != nil { return fmt.Errorf("unable to parse csr %q: %v", csr.Name, err) } - if recognized, err := s.isRequestForSignerFn(x509cr, csr.Spec.Usages, *csr.Spec.SignerName); err != nil { + if recognized, err := s.isRequestForSignerFn(x509cr, csr.Spec.Usages, csr.Spec.SignerName); err != nil { csr.Status.Conditions = append(csr.Status.Conditions, capi.CertificateSigningRequestCondition{ Type: capi.CertificateFailed, Status: v1.ConditionTrue, @@ -162,7 +164,7 @@ func (s *signer) handle(csr *capi.CertificateSigningRequest) error { Message: err.Error(), LastUpdateTime: metav1.Now(), }) - _, err = s.client.CertificatesV1beta1().CertificateSigningRequests().UpdateStatus(context.TODO(), csr, metav1.UpdateOptions{}) + _, err = s.client.CertificatesV1().CertificateSigningRequests().UpdateStatus(context.TODO(), csr, metav1.UpdateOptions{}) if err != nil { return fmt.Errorf("error adding failure condition for csr: %v", err) } @@ -176,7 +178,7 @@ func (s *signer) handle(csr *capi.CertificateSigningRequest) error { return fmt.Errorf("error auto signing csr: %v", err) } csr.Status.Certificate = cert - _, err = s.client.CertificatesV1beta1().CertificateSigningRequests().UpdateStatus(context.TODO(), csr, metav1.UpdateOptions{}) + _, err = s.client.CertificatesV1().CertificateSigningRequests().UpdateStatus(context.TODO(), csr, metav1.UpdateOptions{}) if err != nil { return fmt.Errorf("error updating signature for csr: %v", err) } @@ -208,7 +210,7 @@ func getCSRVerificationFuncForSignerName(signerName string) (isRequestForSignerF return isKubeletClient, nil case capi.KubeAPIServerClientSignerName: return isKubeAPIServerClient, nil - case capi.LegacyUnknownSignerName: + case capiv1beta1.LegacyUnknownSignerName: return isLegacyUnknown, nil default: // TODO type this error so that a different reporting loop (one without a signing cert), can mark @@ -222,14 +224,14 @@ func isKubeletServing(req *x509.CertificateRequest, usages []capi.KeyUsage, sign if signerName != capi.KubeletServingSignerName { return false, nil } - return true, capihelper.ValidateKubeletServingCSR(req, usages) + 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, usages) + return true, capihelper.ValidateKubeletClientCSR(req, usagesToSet(usages)) } func isKubeAPIServerClient(req *x509.CertificateRequest, usages []capi.KeyUsage, signerName string) (bool, error) { @@ -240,11 +242,11 @@ func isKubeAPIServerClient(req *x509.CertificateRequest, usages []capi.KeyUsage, } func isLegacyUnknown(req *x509.CertificateRequest, usages []capi.KeyUsage, signerName string) (bool, error) { - if signerName != capi.LegacyUnknownSignerName { + if signerName != capiv1beta1.LegacyUnknownSignerName { return false, nil } // No restrictions are applied to the legacy-unknown signerName to - // maintain backward compatibility in v1beta1. + // maintain backward compatibility in v1. return true, nil } @@ -265,3 +267,11 @@ func validAPIServerClientUsages(usages []capi.KeyUsage) error { } return nil } + +func usagesToSet(usages []capi.KeyUsage) sets.String { + result := sets.NewString() + for _, usage := range usages { + result.Insert(string(usage)) + } + return result +} diff --git a/pkg/controller/certificates/signer/signer_test.go b/pkg/controller/certificates/signer/signer_test.go index b44c3cb4772..045349a4b77 100644 --- a/pkg/controller/certificates/signer/signer_test.go +++ b/pkg/controller/certificates/signer/signer_test.go @@ -29,7 +29,7 @@ import ( "github.com/google/go-cmp/cmp" - capi "k8s.io/api/certificates/v1beta1" + capi "k8s.io/api/certificates/v1" "k8s.io/apimachinery/pkg/util/clock" "k8s.io/apimachinery/pkg/util/diff" "k8s.io/client-go/kubernetes/fake" @@ -37,13 +37,13 @@ import ( "k8s.io/client-go/util/cert" "k8s.io/kubernetes/pkg/controller/certificates" - capihelper "k8s.io/kubernetes/pkg/apis/certificates/v1beta1" + capihelper "k8s.io/kubernetes/pkg/apis/certificates/v1" ) func TestSigner(t *testing.T) { clock := clock.FakeClock{} - s, err := newSigner(capi.LegacyUnknownSignerName, "./testdata/ca.crt", "./testdata/ca.key", nil, 1*time.Hour) + s, err := newSigner("kubernetes.io/legacy-unknown", "./testdata/ca.crt", "./testdata/ca.key", nil, 1*time.Hour) if err != nil { t.Fatalf("failed to create signer: %v", err) } @@ -337,7 +337,7 @@ func makeTestCSR(b csrBuilder) *capi.CertificateSigningRequest { }, } if b.signerName != "" { - csr.Spec.SignerName = &b.signerName + csr.Spec.SignerName = b.signerName } if b.approved { csr.Status.Conditions = append(csr.Status.Conditions, capi.CertificateSigningRequestCondition{ diff --git a/plugin/pkg/admission/certificates/subjectrestriction/admission.go b/plugin/pkg/admission/certificates/subjectrestriction/admission.go index 1e6e29bcafb..20da7dd7612 100644 --- a/plugin/pkg/admission/certificates/subjectrestriction/admission.go +++ b/plugin/pkg/admission/certificates/subjectrestriction/admission.go @@ -75,7 +75,7 @@ func (p *Plugin) Validate(_ context.Context, a admission.Attributes, _ admission return nil } - csrParsed, err := certificatesapi.ParseCSR(csr) + csrParsed, err := certificatesapi.ParseCSR(csr.Spec.Request) if err != nil { return admission.NewForbidden(a, fmt.Errorf("failed to parse CSR: %v", err)) } diff --git a/test/e2e/framework/.import-restrictions b/test/e2e/framework/.import-restrictions index 896c4f2c4a3..e06fac7c7b7 100644 --- a/test/e2e/framework/.import-restrictions +++ b/test/e2e/framework/.import-restrictions @@ -10,6 +10,7 @@ rules: - k8s.io/kubernetes/pkg/apis/apps/validation - k8s.io/kubernetes/pkg/apis/autoscaling - k8s.io/kubernetes/pkg/apis/batch + - k8s.io/kubernetes/pkg/apis/certificates - k8s.io/kubernetes/pkg/apis/core - k8s.io/kubernetes/pkg/apis/core/helper - k8s.io/kubernetes/pkg/apis/core/install diff --git a/test/integration/certificates/controller_approval_test.go b/test/integration/certificates/controller_approval_test.go index bb52a05a415..228b463c999 100644 --- a/test/integration/certificates/controller_approval_test.go +++ b/test/integration/certificates/controller_approval_test.go @@ -101,7 +101,7 @@ func TestController_AutoApproval(t *testing.T) { informers := informers.NewSharedInformerFactory(clientset.NewForConfigOrDie(restclient.AddUserAgent(s.ClientConfig, "certificatesigningrequest-informers")), time.Second) // Register the controller - c := approver.NewCSRApprovingController(client, informers.Certificates().V1beta1().CertificateSigningRequests()) + c := approver.NewCSRApprovingController(client, informers.Certificates().V1().CertificateSigningRequests()) // Start the controller & informers stopCh := make(chan struct{}) defer close(stopCh) @@ -159,7 +159,7 @@ const ( func waitForCertificateRequestApproved(client kubernetes.Interface, name string) error { if err := wait.Poll(interval, timeout, func() (bool, error) { - csr, err := client.CertificatesV1beta1().CertificateSigningRequests().Get(context.TODO(), name, metav1.GetOptions{}) + csr, err := client.CertificatesV1().CertificateSigningRequests().Get(context.TODO(), name, metav1.GetOptions{}) if err != nil { return false, err }