mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-20 17:38:50 +00:00
Switch CSR approver/signer/cleaner controllers to v1
This commit is contained in:
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user