Merge pull request #91754 from liggitt/csr-v1-client-go-manager
CSR v1 - switch client-go certificate manager utility to v1 by default
This commit is contained in:
@@ -16,13 +16,12 @@ go_library(
|
||||
deps = [
|
||||
"//pkg/kubelet/apis/config:go_default_library",
|
||||
"//pkg/kubelet/metrics: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/types:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/typed/certificates/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/certificate:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/connrotation:go_default_library",
|
||||
|
||||
@@ -11,12 +11,16 @@ go_test(
|
||||
srcs = ["bootstrap_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/api/errors:go_default_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/util/diff:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/typed/certificates/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/keyutil:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -26,12 +30,12 @@ go_library(
|
||||
srcs = ["bootstrap.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubelet/certificate/bootstrap",
|
||||
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/types: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/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes/typed/certificates/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
|
||||
@@ -31,12 +31,12 @@ import (
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
certificates "k8s.io/api/certificates/v1beta1"
|
||||
certificatesv1 "k8s.io/api/certificates/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
certificatesv1beta1 "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
@@ -123,7 +123,7 @@ func LoadClientCert(kubeconfigPath, bootstrapPath, certDir string, nodeName type
|
||||
return fmt.Errorf("unable to load bootstrap kubeconfig: %v", err)
|
||||
}
|
||||
|
||||
bootstrapClient, err := certificatesv1beta1.NewForConfig(bootstrapClientConfig)
|
||||
bootstrapClient, err := clientset.NewForConfig(bootstrapClientConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create certificates signing request client: %v", err)
|
||||
}
|
||||
@@ -160,7 +160,7 @@ func LoadClientCert(kubeconfigPath, bootstrapPath, certDir string, nodeName type
|
||||
klog.Warningf("Error waiting for apiserver to come up: %v", err)
|
||||
}
|
||||
|
||||
certData, err := requestNodeCertificate(bootstrapClient.CertificateSigningRequests(), keyData, nodeName)
|
||||
certData, err := requestNodeCertificate(bootstrapClient, keyData, nodeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -312,7 +312,7 @@ func waitForServer(cfg restclient.Config, deadline time.Duration) error {
|
||||
// certificate (pem-encoded). If there is any errors, or the watch timeouts, it
|
||||
// will return an error. This is intended for use on nodes (kubelet and
|
||||
// kubeadm).
|
||||
func requestNodeCertificate(client certificatesv1beta1.CertificateSigningRequestInterface, privateKeyData []byte, nodeName types.NodeName) (certData []byte, err error) {
|
||||
func requestNodeCertificate(client clientset.Interface, privateKeyData []byte, nodeName types.NodeName) (certData []byte, err error) {
|
||||
subject := &pkix.Name{
|
||||
Organization: []string{"system:nodes"},
|
||||
CommonName: "system:node:" + string(nodeName),
|
||||
@@ -327,10 +327,10 @@ func requestNodeCertificate(client certificatesv1beta1.CertificateSigningRequest
|
||||
return nil, fmt.Errorf("unable to generate certificate request: %v", err)
|
||||
}
|
||||
|
||||
usages := []certificates.KeyUsage{
|
||||
certificates.UsageDigitalSignature,
|
||||
certificates.UsageKeyEncipherment,
|
||||
certificates.UsageClientAuth,
|
||||
usages := []certificatesv1.KeyUsage{
|
||||
certificatesv1.UsageDigitalSignature,
|
||||
certificatesv1.UsageKeyEncipherment,
|
||||
certificatesv1.UsageClientAuth,
|
||||
}
|
||||
|
||||
// The Signer interface contains the Public() method to get the public key.
|
||||
@@ -344,7 +344,7 @@ func requestNodeCertificate(client certificatesv1beta1.CertificateSigningRequest
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := csr.RequestCertificate(client, csrData, name, certificates.KubeAPIServerClientKubeletSignerName, usages, privateKey)
|
||||
reqName, reqUID, err := csr.RequestCertificate(client, csrData, name, certificatesv1.KubeAPIServerClientKubeletSignerName, usages, privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -353,7 +353,7 @@ func requestNodeCertificate(client certificatesv1beta1.CertificateSigningRequest
|
||||
defer cancel()
|
||||
|
||||
klog.V(2).Infof("Waiting for client certificate to be issued")
|
||||
return csr.WaitForCertificate(ctx, client, req)
|
||||
return csr.WaitForCertificate(ctx, client, reqName, reqUID)
|
||||
}
|
||||
|
||||
// This digest should include all the relevant pieces of the CSR we care about.
|
||||
@@ -361,7 +361,7 @@ func requestNodeCertificate(client certificatesv1beta1.CertificateSigningRequest
|
||||
// regenerate every loop and we include usages which are not contained in the
|
||||
// CSR. This needs to be kept up to date as we add new fields to the node
|
||||
// certificates and with ensureCompatible.
|
||||
func digestedName(publicKey interface{}, subject *pkix.Name, usages []certificates.KeyUsage) (string, error) {
|
||||
func digestedName(publicKey interface{}, subject *pkix.Name, usages []certificatesv1.KeyUsage) (string, error) {
|
||||
hash := sha512.New512_256()
|
||||
|
||||
// Here we make sure two different inputs can't write the same stream
|
||||
|
||||
@@ -17,19 +17,22 @@ limitations under the License.
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
certificates "k8s.io/api/certificates/v1beta1"
|
||||
certificatesv1 "k8s.io/api/certificates/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
certificatesclient "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
clienttesting "k8s.io/client-go/testing"
|
||||
"k8s.io/client-go/util/keyutil"
|
||||
)
|
||||
|
||||
@@ -92,7 +95,7 @@ users:
|
||||
}
|
||||
|
||||
func TestRequestNodeCertificateNoKeyData(t *testing.T) {
|
||||
certData, err := requestNodeCertificate(&fakeClient{}, []byte{}, "fake-node-name")
|
||||
certData, err := requestNodeCertificate(newClientset(fakeClient{}), []byte{}, "fake-node-name")
|
||||
if err == nil {
|
||||
t.Errorf("Got no error, wanted error an error because there was an empty private key passed in.")
|
||||
}
|
||||
@@ -102,9 +105,9 @@ func TestRequestNodeCertificateNoKeyData(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRequestNodeCertificateErrorCreatingCSR(t *testing.T) {
|
||||
client := &fakeClient{
|
||||
client := newClientset(fakeClient{
|
||||
failureType: createError,
|
||||
}
|
||||
})
|
||||
privateKeyData, err := keyutil.MakeEllipticPrivateKeyPEM()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to generate a new private key: %v", err)
|
||||
@@ -125,7 +128,7 @@ func TestRequestNodeCertificate(t *testing.T) {
|
||||
t.Fatalf("Unable to generate a new private key: %v", err)
|
||||
}
|
||||
|
||||
certData, err := requestNodeCertificate(&fakeClient{}, privateKeyData, "fake-node-name")
|
||||
certData, err := requestNodeCertificate(newClientset(fakeClient{}), privateKeyData, "fake-node-name")
|
||||
if err != nil {
|
||||
t.Errorf("Got %v, wanted no error.", err)
|
||||
}
|
||||
@@ -144,54 +147,74 @@ const (
|
||||
|
||||
type fakeClient struct {
|
||||
certificatesclient.CertificateSigningRequestInterface
|
||||
watch *watch.FakeWatcher
|
||||
failureType failureType
|
||||
}
|
||||
|
||||
func (c *fakeClient) Create(context.Context, *certificates.CertificateSigningRequest, metav1.CreateOptions) (*certificates.CertificateSigningRequest, error) {
|
||||
if c.failureType == createError {
|
||||
return nil, fmt.Errorf("fakeClient failed creating request")
|
||||
func newClientset(opts fakeClient) *fake.Clientset {
|
||||
f := fake.NewSimpleClientset()
|
||||
switch opts.failureType {
|
||||
case createError:
|
||||
f.PrependReactor("create", "certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
switch action.GetResource().Version {
|
||||
case "v1":
|
||||
return true, nil, fmt.Errorf("create error")
|
||||
default:
|
||||
return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "")
|
||||
}
|
||||
})
|
||||
default:
|
||||
f.PrependReactor("create", "certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
switch action.GetResource().Version {
|
||||
case "v1":
|
||||
return true, &certificatesv1.CertificateSigningRequest{ObjectMeta: metav1.ObjectMeta{Name: "fake-certificate-signing-request-name", UID: "fake-uid"}}, nil
|
||||
default:
|
||||
return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "")
|
||||
}
|
||||
})
|
||||
f.PrependReactor("list", "certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
switch action.GetResource().Version {
|
||||
case "v1":
|
||||
return true, &certificatesv1.CertificateSigningRequestList{Items: []certificatesv1.CertificateSigningRequest{{ObjectMeta: metav1.ObjectMeta{Name: "fake-certificate-signing-request-name", UID: "fake-uid"}}}}, nil
|
||||
default:
|
||||
return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "")
|
||||
}
|
||||
})
|
||||
f.PrependWatchReactor("certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
|
||||
switch action.GetResource().Version {
|
||||
case "v1":
|
||||
w := watch.NewFakeWithChanSize(1, false)
|
||||
w.Add(opts.generateCSR())
|
||||
w.Stop()
|
||||
return true, w, nil
|
||||
|
||||
default:
|
||||
return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "")
|
||||
}
|
||||
})
|
||||
}
|
||||
csr := certificates.CertificateSigningRequest{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: "fake-uid",
|
||||
Name: "fake-certificate-signing-request-name",
|
||||
},
|
||||
}
|
||||
return &csr, nil
|
||||
return f
|
||||
}
|
||||
|
||||
func (c *fakeClient) List(_ context.Context, opts metav1.ListOptions) (*certificates.CertificateSigningRequestList, error) {
|
||||
return &certificates.CertificateSigningRequestList{}, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) Watch(_ context.Context, opts metav1.ListOptions) (watch.Interface, error) {
|
||||
c.watch = watch.NewFakeWithChanSize(1, false)
|
||||
c.watch.Add(c.generateCSR())
|
||||
c.watch.Stop()
|
||||
return c.watch, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) generateCSR() *certificates.CertificateSigningRequest {
|
||||
var condition certificates.CertificateSigningRequestCondition
|
||||
func (c fakeClient) generateCSR() runtime.Object {
|
||||
var condition certificatesv1.CertificateSigningRequestCondition
|
||||
var certificateData []byte
|
||||
if c.failureType == certificateSigningRequestDenied {
|
||||
condition = certificates.CertificateSigningRequestCondition{
|
||||
Type: certificates.CertificateDenied,
|
||||
condition = certificatesv1.CertificateSigningRequestCondition{
|
||||
Type: certificatesv1.CertificateDenied,
|
||||
}
|
||||
} else {
|
||||
condition = certificates.CertificateSigningRequestCondition{
|
||||
Type: certificates.CertificateApproved,
|
||||
condition = certificatesv1.CertificateSigningRequestCondition{
|
||||
Type: certificatesv1.CertificateApproved,
|
||||
}
|
||||
certificateData = []byte(`issued certificate`)
|
||||
}
|
||||
|
||||
csr := certificates.CertificateSigningRequest{
|
||||
csr := certificatesv1.CertificateSigningRequest{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: "fake-uid",
|
||||
},
|
||||
Status: certificates.CertificateSigningRequestStatus{
|
||||
Conditions: []certificates.CertificateSigningRequestCondition{
|
||||
Status: certificatesv1.CertificateSigningRequestStatus{
|
||||
Conditions: []certificatesv1.CertificateSigningRequestCondition{
|
||||
condition,
|
||||
},
|
||||
Certificate: certificateData,
|
||||
|
||||
@@ -26,11 +26,10 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
certificates "k8s.io/api/certificates/v1beta1"
|
||||
certificates "k8s.io/api/certificates/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
certificatesclient "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
|
||||
"k8s.io/client-go/util/certificate"
|
||||
compbasemetrics "k8s.io/component-base/metrics"
|
||||
"k8s.io/component-base/metrics/legacyregistry"
|
||||
@@ -41,9 +40,11 @@ import (
|
||||
// NewKubeletServerCertificateManager creates a certificate manager for the kubelet when retrieving a server certificate
|
||||
// or returns an error.
|
||||
func NewKubeletServerCertificateManager(kubeClient clientset.Interface, kubeCfg *kubeletconfig.KubeletConfiguration, nodeName types.NodeName, getAddresses func() []v1.NodeAddress, certDirectory string) (certificate.Manager, error) {
|
||||
var certSigningRequestClient certificatesclient.CertificateSigningRequestInterface
|
||||
if kubeClient != nil && kubeClient.CertificatesV1beta1() != nil {
|
||||
certSigningRequestClient = kubeClient.CertificatesV1beta1().CertificateSigningRequests()
|
||||
var clientsetFn certificate.ClientsetFunc
|
||||
if kubeClient != nil {
|
||||
clientsetFn = func(current *tls.Certificate) (clientset.Interface, error) {
|
||||
return kubeClient, nil
|
||||
}
|
||||
}
|
||||
certificateStore, err := certificate.NewFileStore(
|
||||
"kubelet-server",
|
||||
@@ -103,9 +104,7 @@ func NewKubeletServerCertificateManager(kubeClient clientset.Interface, kubeCfg
|
||||
}
|
||||
|
||||
m, err := certificate.NewManager(&certificate.Config{
|
||||
ClientFn: func(current *tls.Certificate) (certificatesclient.CertificateSigningRequestInterface, error) {
|
||||
return certSigningRequestClient, nil
|
||||
},
|
||||
ClientsetFn: clientsetFn,
|
||||
GetTemplate: getTemplate,
|
||||
SignerName: certificates.KubeletServingSignerName,
|
||||
Usages: []certificates.KeyUsage{
|
||||
@@ -198,7 +197,7 @@ func NewKubeletClientCertificateManager(
|
||||
bootstrapKeyData []byte,
|
||||
certFile string,
|
||||
keyFile string,
|
||||
clientFn certificate.CSRClientFunc,
|
||||
clientsetFn certificate.ClientsetFunc,
|
||||
) (certificate.Manager, error) {
|
||||
|
||||
certificateStore, err := certificate.NewFileStore(
|
||||
@@ -222,7 +221,7 @@ func NewKubeletClientCertificateManager(
|
||||
legacyregistry.Register(certificateRenewFailure)
|
||||
|
||||
m, err := certificate.NewManager(&certificate.Config{
|
||||
ClientFn: clientFn,
|
||||
ClientsetFn: clientsetFn,
|
||||
Template: &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("system:node:%s", nodeName),
|
||||
|
||||
Reference in New Issue
Block a user