mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-06 18:54:06 +00:00
Mechanism for renewing a certificate based on an existing certificate
This commit is contained in:
parent
7e3340361a
commit
ab28409da3
24
cmd/kubeadm/app/cmd/options/certs.go
Normal file
24
cmd/kubeadm/app/cmd/options/certs.go
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package options
|
||||
|
||||
import "github.com/spf13/pflag"
|
||||
|
||||
// AddCertificateDirFlag adds the --certs-dir flag to the given flagset
|
||||
func AddCertificateDirFlag(fs *pflag.FlagSet, certsDir *string) {
|
||||
fs.StringVar(certsDir, "cert-dir", *certsDir, "The path where to save the certificates")
|
||||
}
|
@ -25,6 +25,7 @@ import (
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
||||
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
@ -184,8 +185,8 @@ func getSANDescription(certSpec *certsphase.KubeadmCert) string {
|
||||
}
|
||||
|
||||
func addFlags(cmd *cobra.Command, cfgPath *string, cfg *kubeadmapiv1alpha3.InitConfiguration, addAPIFlags bool) {
|
||||
cmd.Flags().StringVar(cfgPath, "config", *cfgPath, "Path to kubeadm config file. WARNING: Usage of a configuration file is experimental")
|
||||
cmd.Flags().StringVar(&cfg.CertificatesDir, "cert-dir", cfg.CertificatesDir, "The path where to save the certificates")
|
||||
options.AddCertificateDirFlag(cmd.Flags(), &cfg.CertificatesDir)
|
||||
options.AddKubeConfigFlag(cmd.Flags(), cfgPath)
|
||||
if addAPIFlags {
|
||||
cmd.Flags().StringVar(&cfg.Networking.DNSDomain, "service-dns-domain", cfg.Networking.DNSDomain, "Alternative domain for services, to use for the API server serving cert")
|
||||
cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, "Alternative range of IP address for service VIPs, from which derives the internal API server VIP that will be added to the API Server serving cert")
|
||||
|
42
cmd/kubeadm/app/cmd/phases/certs/BUILD
Normal file
42
cmd/kubeadm/app/cmd/phases/certs/BUILD
Normal file
@ -0,0 +1,42 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["renew.go"],
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/certs",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/apis/kubeadm/scheme:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha3:go_default_library",
|
||||
"//cmd/kubeadm/app/cmd/options:go_default_library",
|
||||
"//cmd/kubeadm/app/cmd/util:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs:go_default_library",
|
||||
"//cmd/kubeadm/app/phases/certs/renewal:go_default_library",
|
||||
"//cmd/kubeadm/app/util:go_default_library",
|
||||
"//cmd/kubeadm/app/util/config:go_default_library",
|
||||
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["renewal_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//vendor/github.com/spf13/cobra:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
124
cmd/kubeadm/app/cmd/phases/certs/renew.go
Normal file
124
cmd/kubeadm/app/cmd/phases/certs/renew.go
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package renew
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
|
||||
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/renewal"
|
||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
|
||||
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
|
||||
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
||||
)
|
||||
|
||||
func NewCmdCertsRenewal() *cobra.Command {
|
||||
cfg := &renewConfig{
|
||||
kubeconfigPath: constants.GetAdminKubeConfigPath(),
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "renew",
|
||||
Short: "Renews all known certificates for kubeadm",
|
||||
Long: "", // TODO EKF fill out
|
||||
}
|
||||
addFlags(cmd, cfg)
|
||||
|
||||
cmd.AddCommand(getRenewSubCommands(cfg)...)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
type renewConfig struct {
|
||||
cfgPath string
|
||||
kubeconfigPath string
|
||||
cfg kubeadmapiv1alpha3.InitConfiguration
|
||||
useAPI bool
|
||||
}
|
||||
|
||||
func getRenewSubCommands(cfg *renewConfig) []*cobra.Command {
|
||||
// Default values for the cobra help text
|
||||
kubeadmscheme.Scheme.Default(&cfg.cfg)
|
||||
|
||||
certTree, err := certsphase.GetDefaultCertList().AsMap().CertTree()
|
||||
kubeadmutil.CheckErr(err)
|
||||
|
||||
cmdList := []*cobra.Command{}
|
||||
|
||||
for caCert, certs := range certTree {
|
||||
// Don't offer to renew CAs; would cause serious consequences
|
||||
for _, cert := range certs {
|
||||
cmdList = append(cmdList, makeCommandForRenew(cert, caCert, cfg))
|
||||
}
|
||||
}
|
||||
|
||||
return cmdList
|
||||
}
|
||||
|
||||
func addFlags(cmd *cobra.Command, cfg *renewConfig) {
|
||||
options.AddConfigFlag(cmd.Flags(), &cfg.cfgPath)
|
||||
options.AddCertificateDirFlag(cmd.Flags(), &cfg.cfg.CertificatesDir)
|
||||
options.AddKubeConfigFlag(cmd.Flags(), &cfg.kubeconfigPath)
|
||||
cmd.Flags().BoolVar(&cfg.useAPI, "use-api", cfg.useAPI, "Use the kubernetes certificate API to renew certificates")
|
||||
}
|
||||
|
||||
func generateCertCommand(name, longName string) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: name,
|
||||
Short: fmt.Sprintf("Generates the %s", longName),
|
||||
Long: "", // TODO EKF fill out
|
||||
}
|
||||
}
|
||||
|
||||
func makeCommandForRenew(cert *certsphase.KubeadmCert, caCert *certsphase.KubeadmCert, cfg *renewConfig) *cobra.Command {
|
||||
certCmd := generateCertCommand(cert.Name, cert.LongName)
|
||||
addFlags(certCmd, cfg)
|
||||
|
||||
certCmd.Run = func(cmd *cobra.Command, args []string) {
|
||||
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfg.cfgPath, &cfg.cfg)
|
||||
kubeadmutil.CheckErr(err)
|
||||
|
||||
renewer, err := getRenewer(cfg, caCert)
|
||||
}
|
||||
return certCmd
|
||||
}
|
||||
|
||||
func getRenewer(cfg *renewConfig, caCertSpec *certsphase.KubeadmCert) (renewal.Interface, error) {
|
||||
if cfg.useAPI {
|
||||
kubeConfigPath := cmdutil.FindExistingKubeConfig(cfg.kubeconfigPath)
|
||||
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return renewal.NewCertsAPIRenawal(client), nil
|
||||
}
|
||||
|
||||
caCert, caKey, err := certsphase.LoadCertificateAuthority(cfg.cfg.CertificatesDir, caCertSpec.BaseName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return renewal.NewFileRenewal(caCert, caKey), nil
|
||||
}
|
66
cmd/kubeadm/app/cmd/phases/certs/renewal_test.go
Normal file
66
cmd/kubeadm/app/cmd/phases/certs/renewal_test.go
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package renew
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func TestCommandsGenerated(t *testing.T) {
|
||||
expectedFlags := []string{
|
||||
"cert-dir",
|
||||
"config",
|
||||
"use-api",
|
||||
}
|
||||
|
||||
expectedCommands := []string{
|
||||
"renew",
|
||||
|
||||
"renew apiserver",
|
||||
"renew apiserver-kubelet-client",
|
||||
"renew apiserver-etcd-client",
|
||||
|
||||
"renew front-proxy-client",
|
||||
|
||||
"renew etcd-server",
|
||||
"renew etcd-peer",
|
||||
"renew etcd-healthcheck-client",
|
||||
}
|
||||
|
||||
renewCmd := NewCmdCertsRenewal()
|
||||
|
||||
fakeRoot := &cobra.Command{}
|
||||
fakeRoot.AddCommand(renewCmd)
|
||||
|
||||
for _, cmdPath := range expectedCommands {
|
||||
t.Run(cmdPath, func(t *testing.T) {
|
||||
cmd, rem, _ := fakeRoot.Find(strings.Split(cmdPath, " "))
|
||||
if cmd == nil || len(rem) != 0 {
|
||||
t.Fatalf("couldn't locate command %q (%v)", cmdPath, rem)
|
||||
}
|
||||
|
||||
for _, flag := range expectedFlags {
|
||||
if cmd.Flags().Lookup(flag) == nil {
|
||||
t.Errorf("couldn't find expected flag --%s", flag)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -137,7 +137,7 @@ func CreateCertAndKeyFilesWithCA(certSpec *KubeadmCert, caCertSpec *KubeadmCert,
|
||||
return fmt.Errorf("Expected CAname for %s to be %q, but was %s", certSpec.Name, certSpec.CAName, caCertSpec.Name)
|
||||
}
|
||||
|
||||
caCert, caKey, err := loadCertificateAuthority(cfg.CertificatesDir, caCertSpec.BaseName)
|
||||
caCert, caKey, err := LoadCertificateAuthority(cfg.CertificatesDir, caCertSpec.BaseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Couldn't load CA certificate %s: %v", caCertSpec.Name, err)
|
||||
}
|
||||
@ -158,7 +158,8 @@ func newCertAndKeyFromSpec(certSpec *KubeadmCert, cfg *kubeadmapi.InitConfigurat
|
||||
return cert, key, err
|
||||
}
|
||||
|
||||
func loadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
// LoadCertificateAuthority tries to load a CA in the given directory with the given name.
|
||||
func LoadCertificateAuthority(pkiDir string, baseName string) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
// Checks if certificate authority exists in the PKI directory
|
||||
if !pkiutil.CertOrKeyExist(pkiDir, baseName) {
|
||||
return nil, nil, fmt.Errorf("couldn't load %s certificate authority from %s", baseName, pkiDir)
|
||||
|
@ -17,8 +17,8 @@ limitations under the License.
|
||||
package renewal
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"errors"
|
||||
@ -55,7 +55,7 @@ func NewCertsAPIRenawal(client kubernetes.Interface) Interface {
|
||||
}
|
||||
|
||||
// Renew takes a certificate using the cert and key.
|
||||
func (r *CertsAPIRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, crypto.PrivateKey, error) {
|
||||
func (r *CertsAPIRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
reqTmp := &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: cfg.CommonName,
|
||||
|
@ -17,10 +17,8 @@ limitations under the License.
|
||||
package renewal
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
|
||||
@ -29,11 +27,11 @@ import (
|
||||
// FileRenewal renews a certificate using local certs
|
||||
type FileRenewal struct {
|
||||
caCert *x509.Certificate
|
||||
caKey crypto.PrivateKey
|
||||
caKey *rsa.PrivateKey
|
||||
}
|
||||
|
||||
// NewFileRenewal takes a certificate pair to construct the Interface.
|
||||
func NewFileRenewal(caCert *x509.Certificate, caKey crypto.PrivateKey) Interface {
|
||||
func NewFileRenewal(caCert *x509.Certificate, caKey *rsa.PrivateKey) Interface {
|
||||
return &FileRenewal{
|
||||
caCert: caCert,
|
||||
caKey: caKey,
|
||||
@ -41,11 +39,6 @@ func NewFileRenewal(caCert *x509.Certificate, caKey crypto.PrivateKey) Interface
|
||||
}
|
||||
|
||||
// Renew takes a certificate using the cert and key
|
||||
func (r *FileRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, crypto.PrivateKey, error) {
|
||||
caKey, ok := r.caKey.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("unsupported private key type %t", r.caKey)
|
||||
}
|
||||
|
||||
return pkiutil.NewCertAndKey(r.caCert, caKey, cfg)
|
||||
func (r *FileRenewal) Renew(cfg *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
return pkiutil.NewCertAndKey(r.caCert, r.caKey, cfg)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||
package renewal
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
@ -25,5 +25,5 @@ import (
|
||||
|
||||
// Interface represents a standard way to renew a certificate.
|
||||
type Interface interface {
|
||||
Renew(*certutil.Config) (*x509.Certificate, crypto.PrivateKey, error)
|
||||
Renew(*certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error)
|
||||
}
|
||||
|
55
cmd/kubeadm/app/phases/certs/renewal/renewal.go
Normal file
55
cmd/kubeadm/app/phases/certs/renewal/renewal.go
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package renewal
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
|
||||
)
|
||||
|
||||
func RenewExistingCert(certsDir, baseName string, impl Interface) error {
|
||||
cert, err := pkiutil.TryLoadCertFromDisk(certsDir, baseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load existing certificate %s: %v", baseName, err)
|
||||
}
|
||||
|
||||
cfg := certToConfig(cert)
|
||||
newCert, newKey, err := impl.Renew(cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to renew certificate %s: %v", baseName, err)
|
||||
}
|
||||
|
||||
if err := pkiutil.WriteCertAndKey(certsDir, baseName, newCert, newKey); err != nil {
|
||||
return fmt.Errorf("failed to write new certificate %s: %v", baseName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func certToConfig(cert *x509.Certificate) *certutil.Config {
|
||||
return &certutil.Config{
|
||||
CommonName: cert.Subject.CommonName,
|
||||
Organization: cert.Subject.Organization,
|
||||
AltNames: certutil.AltNames{
|
||||
IPs: cert.IPAddresses,
|
||||
DNSNames: cert.DNSNames,
|
||||
},
|
||||
Usages: cert.ExtKeyUsage,
|
||||
}
|
||||
}
|
@ -19,6 +19,9 @@ package renewal
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -31,6 +34,8 @@ import (
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
|
||||
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
|
||||
certtestutil "k8s.io/kubernetes/cmd/kubeadm/test/certs"
|
||||
)
|
||||
|
||||
func TestRenewImplementations(t *testing.T) {
|
||||
@ -131,3 +136,100 @@ func getCertReq(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey) *
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertToConfig(t *testing.T) {
|
||||
expectedConfig := &certutil.Config{
|
||||
CommonName: "test-common-name",
|
||||
Organization: []string{"sig-cluster-lifecycle"},
|
||||
AltNames: certutil.AltNames{
|
||||
IPs: []net.IP{net.ParseIP("10.100.0.1")},
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
|
||||
cert := &x509.Certificate{
|
||||
Subject: pkix.Name{
|
||||
CommonName: "test-common-name",
|
||||
Organization: []string{"sig-cluster-lifecycle"},
|
||||
},
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
IPAddresses: []net.IP{net.ParseIP("10.100.0.1")},
|
||||
}
|
||||
|
||||
cfg := certToConfig(cert)
|
||||
|
||||
if cfg.CommonName != expectedConfig.CommonName {
|
||||
t.Errorf("expected common name %q, got %q", expectedConfig.CommonName, cfg.CommonName)
|
||||
}
|
||||
|
||||
if len(cfg.Organization) != 1 || cfg.Organization[0] != expectedConfig.Organization[0] {
|
||||
t.Errorf("expected organization %v, got %v", expectedConfig.Organization, cfg.Organization)
|
||||
|
||||
}
|
||||
|
||||
if len(cfg.Usages) != 1 || cfg.Usages[0] != expectedConfig.Usages[0] {
|
||||
t.Errorf("expected ext key usage %v, got %v", expectedConfig.Usages, cfg.Usages)
|
||||
}
|
||||
|
||||
if len(cfg.AltNames.IPs) != 1 || cfg.AltNames.IPs[0].String() != expectedConfig.AltNames.IPs[0].String() {
|
||||
t.Errorf("expected SAN IPs %v, got %v", expectedConfig.AltNames.IPs, cfg.AltNames.IPs)
|
||||
}
|
||||
|
||||
if len(cfg.AltNames.DNSNames) != 1 || cfg.AltNames.DNSNames[0] != expectedConfig.AltNames.DNSNames[0] {
|
||||
t.Errorf("expected SAN DNSNames %v, got %v", expectedConfig.AltNames.DNSNames, cfg.AltNames.DNSNames)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenewExistingCert(t *testing.T) {
|
||||
cfg := &certutil.Config{
|
||||
CommonName: "test-common-name",
|
||||
Organization: []string{"sig-cluster-lifecycle"},
|
||||
AltNames: certutil.AltNames{
|
||||
IPs: []net.IP{net.ParseIP("10.100.0.1")},
|
||||
DNSNames: []string{"test-domain.space"},
|
||||
},
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
|
||||
caCertCfg := &certutil.Config{CommonName: "kubernetes"}
|
||||
caCert, caKey, err := certs.NewCACertAndKey(caCertCfg)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't create CA: %v", err)
|
||||
}
|
||||
|
||||
cert, key, err := pkiutil.NewCertAndKey(caCert, caKey, cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't generate certificate: %v", err)
|
||||
}
|
||||
|
||||
dir := testutil.SetupTempDir(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
if err := pkiutil.WriteCertAndKey(dir, "server", cert, key); err != nil {
|
||||
t.Fatalf("couldn't write out certificate")
|
||||
}
|
||||
|
||||
renewer := NewFileRenewal(caCert, caKey)
|
||||
|
||||
if err := RenewExistingCert(dir, "server", renewer); err != nil {
|
||||
t.Fatalf("couldn't renew certificate: %v", err)
|
||||
}
|
||||
|
||||
newCert, err := pkiutil.TryLoadCertFromDisk(dir, "server")
|
||||
if err != nil {
|
||||
t.Fatalf("couldn't load created certificate: %v", err)
|
||||
}
|
||||
|
||||
if newCert.SerialNumber.Cmp(cert.SerialNumber) == 0 {
|
||||
t.Fatal("expected new certificate, but renewed certificate has same serial number")
|
||||
}
|
||||
|
||||
certtestutil.AssertCertificateIsSignedByCa(t, newCert, caCert)
|
||||
certtestutil.AssertCertificateHasClientAuthUsage(t, newCert)
|
||||
certtestutil.AssertCertificateHasOrganizations(t, newCert, cfg.Organization...)
|
||||
certtestutil.AssertCertificateHasCommonName(t, newCert, cfg.CommonName)
|
||||
certtestutil.AssertCertificateHasDNSNames(t, newCert, cfg.AltNames.DNSNames...)
|
||||
certtestutil.AssertCertificateHasIPAddresses(t, newCert, cfg.AltNames.IPs...)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user