allow setting different certificates for kube-controller-managed CSR signers

This commit is contained in:
David Eads 2020-05-06 16:02:31 -04:00
parent a26e5881d8
commit e88fecf26b
9 changed files with 556 additions and 82 deletions

View File

@ -471,9 +471,15 @@ API rule violation: names_match,k8s.io/apimachinery/pkg/util/intstr,IntOrString,
API rule violation: names_match,k8s.io/apimachinery/pkg/util/intstr,IntOrString,Type
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,AttachDetachControllerConfiguration,DisableAttachDetachReconcilerSync
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,AttachDetachControllerConfiguration,ReconcilerSyncLoopPeriod
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,CSRSigningConfiguration,CertFile
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,CSRSigningConfiguration,KeyFile
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,CSRSigningControllerConfiguration,ClusterSigningCertFile
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,CSRSigningControllerConfiguration,ClusterSigningDuration
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,CSRSigningControllerConfiguration,ClusterSigningKeyFile
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,CSRSigningControllerConfiguration,KubeAPIServerClientSignerConfiguration
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,CSRSigningControllerConfiguration,KubeletClientSignerConfiguration
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,CSRSigningControllerConfiguration,KubeletServingSignerConfiguration
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,CSRSigningControllerConfiguration,LegacyUnknownSignerConfiguration
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,CloudProviderConfiguration,CloudConfigFile
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,CloudProviderConfiguration,Name
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,DaemonSetControllerConfiguration,ConcurrentDaemonSetSyncs

View File

@ -158,9 +158,13 @@ go_library(
go_test(
name = "go_default_test",
srcs = ["core_test.go"],
srcs = [
"certificates_test.go",
"core_test.go",
],
embed = [":go_default_library"],
deps = [
"//pkg/controller/certificates/signer/config:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/client-go/discovery:go_default_library",
"//staging/src/k8s.io/client-go/discovery/fake:go_default_library",

View File

@ -22,14 +22,11 @@ package app
import (
"fmt"
"os"
"net/http"
"k8s.io/apimachinery/pkg/runtime/schema"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/klog/v2"
kubeoptions "k8s.io/kubernetes/cmd/kube-controller-manager/app/options"
"k8s.io/kubernetes/pkg/controller/certificates/approver"
"k8s.io/kubernetes/pkg/controller/certificates/cleaner"
"k8s.io/kubernetes/pkg/controller/certificates/rootcacertpublisher"
@ -44,87 +41,129 @@ func startCSRSigningController(ctx ControllerContext) (http.Handler, bool, error
klog.Warningf("Resource %s is not available now", gvr.String())
return nil, false, nil
}
if ctx.ComponentConfig.CSRSigningController.ClusterSigningCertFile == "" || ctx.ComponentConfig.CSRSigningController.ClusterSigningKeyFile == "" {
missingSingleSigningFile := ctx.ComponentConfig.CSRSigningController.ClusterSigningCertFile == "" || ctx.ComponentConfig.CSRSigningController.ClusterSigningKeyFile == ""
if missingSingleSigningFile && !anySpecificFilesSet(ctx.ComponentConfig.CSRSigningController) {
klog.V(2).Info("skipping CSR signer controller because no csr cert/key was specified")
return nil, false, nil
}
// Deprecation warning for old defaults.
//
// * If the signing cert and key are the default paths but the files
// exist, warn that the paths need to be specified explicitly in a
// later release and the defaults will be removed. We don't expect this
// to be the case.
//
// * If the signing cert and key are default paths but the files don't exist,
// bail out of startController without logging.
var keyFileExists, keyUsesDefault, certFileExists, certUsesDefault bool
_, err := os.Stat(ctx.ComponentConfig.CSRSigningController.ClusterSigningCertFile)
certFileExists = !os.IsNotExist(err)
certUsesDefault = (ctx.ComponentConfig.CSRSigningController.ClusterSigningCertFile == kubeoptions.DefaultClusterSigningCertFile)
_, err = os.Stat(ctx.ComponentConfig.CSRSigningController.ClusterSigningKeyFile)
keyFileExists = !os.IsNotExist(err)
keyUsesDefault = (ctx.ComponentConfig.CSRSigningController.ClusterSigningKeyFile == kubeoptions.DefaultClusterSigningKeyFile)
switch {
case (keyFileExists && keyUsesDefault) || (certFileExists && certUsesDefault):
klog.Warningf("You might be using flag defaulting for --cluster-signing-cert-file and" +
" --cluster-signing-key-file. These defaults are deprecated and will be removed" +
" in a subsequent release. Please pass these options explicitly.")
case (!keyFileExists && keyUsesDefault) && (!certFileExists && certUsesDefault):
// This is what we expect right now if people aren't
// setting up the signing controller. This isn't
// actually a problem since the signer is not a
// required controller.
klog.V(2).Info("skipping CSR signer controller because no csr cert/key was specified and the default files are missing")
return nil, false, nil
default:
// Note that '!filesExist && !usesDefaults' is obviously
// operator error. We don't handle this case here and instead
// allow it to be handled by NewCSR... below.
if !missingSingleSigningFile && anySpecificFilesSet(ctx.ComponentConfig.CSRSigningController) {
return nil, false, fmt.Errorf("cannot specify default and per controller certs at the same time")
}
c := ctx.ClientBuilder.ClientOrDie("certificate-controller")
csrInformer := ctx.InformerFactory.Certificates().V1().CertificateSigningRequests()
certTTL := ctx.ComponentConfig.CSRSigningController.ClusterSigningDuration.Duration
caFile, caKeyFile := getKubeletServingSignerFiles(ctx.ComponentConfig.CSRSigningController)
// TODO get different signer cert and key files for each signer when we add flags.
kubeletServingSigner, err := signer.NewKubeletServingCSRSigningController(c, csrInformer, caFile, caKeyFile, certTTL)
if kubeletServingSignerCertFile, kubeletServingSignerKeyFile := getKubeletServingSignerFiles(ctx.ComponentConfig.CSRSigningController); len(kubeletServingSignerCertFile) > 0 || len(kubeletServingSignerKeyFile) > 0 {
kubeletServingSigner, err := signer.NewKubeletServingCSRSigningController(c, csrInformer, kubeletServingSignerCertFile, kubeletServingSignerKeyFile, certTTL)
if err != nil {
return nil, false, fmt.Errorf("failed to start kubernetes.io/kubelet-serving certificate controller: %v", err)
}
go kubeletServingSigner.Run(1, ctx.Stop)
} else {
klog.V(2).Infof("skipping CSR signer controller %q because specific files were specified for other signers and not this one.", "kubernetes.io/kubelet-serving")
}
kubeletClientSigner, err := signer.NewKubeletClientCSRSigningController(c, csrInformer, caFile, caKeyFile, certTTL)
if kubeletClientSignerCertFile, kubeletClientSignerKeyFile := getKubeletClientSignerFiles(ctx.ComponentConfig.CSRSigningController); len(kubeletClientSignerCertFile) > 0 || len(kubeletClientSignerKeyFile) > 0 {
kubeletClientSigner, err := signer.NewKubeletClientCSRSigningController(c, csrInformer, kubeletClientSignerCertFile, kubeletClientSignerKeyFile, certTTL)
if err != nil {
return nil, false, fmt.Errorf("failed to start kubernetes.io/kube-apiserver-client-kubelet certificate controller: %v", err)
}
go kubeletClientSigner.Run(1, ctx.Stop)
} else {
klog.V(2).Infof("skipping CSR signer controller %q because specific files were specified for other signers and not this one.", "kubernetes.io/kube-apiserver-client-kubelet")
}
kubeAPIServerClientSigner, err := signer.NewKubeAPIServerClientCSRSigningController(c, csrInformer, caFile, caKeyFile, certTTL)
if kubeAPIServerSignerCertFile, kubeAPIServerSignerKeyFile := getKubeAPIServerClientSignerFiles(ctx.ComponentConfig.CSRSigningController); len(kubeAPIServerSignerCertFile) > 0 || len(kubeAPIServerSignerKeyFile) > 0 {
kubeAPIServerClientSigner, err := signer.NewKubeAPIServerClientCSRSigningController(c, csrInformer, kubeAPIServerSignerCertFile, kubeAPIServerSignerKeyFile, certTTL)
if err != nil {
return nil, false, fmt.Errorf("failed to start kubernetes.io/kube-apiserver-client certificate controller: %v", err)
}
go kubeAPIServerClientSigner.Run(1, ctx.Stop)
} else {
klog.V(2).Infof("skipping CSR signer controller %q because specific files were specified for other signers and not this one.", "kubernetes.io/kube-apiserver-client")
}
legacyUnknownSigner, err := signer.NewLegacyUnknownCSRSigningController(c, csrInformer, caFile, caKeyFile, certTTL)
if legacyUnknownSignerCertFile, legacyUnknownSignerKeyFile := getLegacyUnknownSignerFiles(ctx.ComponentConfig.CSRSigningController); len(legacyUnknownSignerCertFile) > 0 || len(legacyUnknownSignerKeyFile) > 0 {
legacyUnknownSigner, err := signer.NewLegacyUnknownCSRSigningController(c, csrInformer, legacyUnknownSignerCertFile, legacyUnknownSignerKeyFile, certTTL)
if err != nil {
return nil, false, fmt.Errorf("failed to start kubernetes.io/legacy-unknown certificate controller: %v", err)
}
go legacyUnknownSigner.Run(1, ctx.Stop)
} else {
klog.V(2).Infof("skipping CSR signer controller %q because specific files were specified for other signers and not this one.", "kubernetes.io/legacy-unknown")
}
return nil, true, nil
}
// getKubeletServingSignerFiles returns the cert and key for signing.
// TODO we will extended this for each signer so that it prefers the specific flag (to be added) and falls back to the single flag
func areKubeletServingSignerFilesSpecified(config csrsigningconfig.CSRSigningControllerConfiguration) bool {
if len(config.KubeletServingSignerConfiguration.CertFile) > 0 || len(config.KubeletServingSignerConfiguration.KeyFile) > 0 {
// if only one is specified, it will error later during construction
return true
}
return false
}
func areKubeletClientSignerFilesSpecified(config csrsigningconfig.CSRSigningControllerConfiguration) bool {
if len(config.KubeletClientSignerConfiguration.CertFile) > 0 || len(config.KubeletClientSignerConfiguration.KeyFile) > 0 {
// if only one is specified, it will error later during construction
return true
}
return false
}
func areKubeAPIServerClientSignerFilesSpecified(config csrsigningconfig.CSRSigningControllerConfiguration) bool {
if len(config.KubeAPIServerClientSignerConfiguration.CertFile) > 0 || len(config.KubeAPIServerClientSignerConfiguration.KeyFile) > 0 {
// if only one is specified, it will error later during construction
return true
}
return false
}
func areLegacyUnknownSignerFilesSpecified(config csrsigningconfig.CSRSigningControllerConfiguration) bool {
if len(config.LegacyUnknownSignerConfiguration.CertFile) > 0 || len(config.LegacyUnknownSignerConfiguration.KeyFile) > 0 {
// if only one is specified, it will error later during construction
return true
}
return false
}
func anySpecificFilesSet(config csrsigningconfig.CSRSigningControllerConfiguration) bool {
return areKubeletServingSignerFilesSpecified(config) ||
areKubeletClientSignerFilesSpecified(config) ||
areKubeAPIServerClientSignerFilesSpecified(config) ||
areLegacyUnknownSignerFilesSpecified(config)
}
func getKubeletServingSignerFiles(config csrsigningconfig.CSRSigningControllerConfiguration) (string, string) {
// if any cert/key is set for specific CSR signing loops, then the --cluster-signing-{cert,key}-file are not used for any CSR signing loop.
if anySpecificFilesSet(config) {
return config.KubeletServingSignerConfiguration.CertFile, config.KubeletServingSignerConfiguration.KeyFile
}
return config.ClusterSigningCertFile, config.ClusterSigningKeyFile
}
func getKubeletClientSignerFiles(config csrsigningconfig.CSRSigningControllerConfiguration) (string, string) {
// if any cert/key is set for specific CSR signing loops, then the --cluster-signing-{cert,key}-file are not used for any CSR signing loop.
if anySpecificFilesSet(config) {
return config.KubeletClientSignerConfiguration.CertFile, config.KubeletClientSignerConfiguration.KeyFile
}
return config.ClusterSigningCertFile, config.ClusterSigningKeyFile
}
func getKubeAPIServerClientSignerFiles(config csrsigningconfig.CSRSigningControllerConfiguration) (string, string) {
// if any cert/key is set for specific CSR signing loops, then the --cluster-signing-{cert,key}-file are not used for any CSR signing loop.
if anySpecificFilesSet(config) {
return config.KubeAPIServerClientSignerConfiguration.CertFile, config.KubeAPIServerClientSignerConfiguration.KeyFile
}
return config.ClusterSigningCertFile, config.ClusterSigningKeyFile
}
func getLegacyUnknownSignerFiles(config csrsigningconfig.CSRSigningControllerConfiguration) (string, string) {
// if any cert/key is set for specific CSR signing loops, then the --cluster-signing-{cert,key}-file are not used for any CSR signing loop.
if anySpecificFilesSet(config) {
return config.LegacyUnknownSignerConfiguration.CertFile, config.LegacyUnknownSignerConfiguration.KeyFile
}
return config.ClusterSigningCertFile, config.ClusterSigningKeyFile
}

View File

@ -0,0 +1,309 @@
/*
Copyright 2020 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 app
import (
"testing"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
csrsigningconfig "k8s.io/kubernetes/pkg/controller/certificates/signer/config"
)
func TestCertSpecified(t *testing.T) {
allConfig := csrsigningconfig.CSRSigningControllerConfiguration{
ClusterSigningCertFile: "/cluster-signing-cert",
ClusterSigningKeyFile: "/cluster-signing-key",
ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kubelet-serving/cert-file",
KeyFile: "/cluster-signing-kubelet-serving/key-file",
},
KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kubelet-client/cert-file",
KeyFile: "/cluster-signing-kubelet-client/key-file",
},
KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
},
LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-legacy-unknown/cert-file",
KeyFile: "/cluster-signing-legacy-unknown/key-file",
},
}
defaultOnly := csrsigningconfig.CSRSigningControllerConfiguration{
ClusterSigningCertFile: "/cluster-signing-cert",
ClusterSigningKeyFile: "/cluster-signing-key",
ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
}
specifiedOnly := csrsigningconfig.CSRSigningControllerConfiguration{
KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kubelet-serving/cert-file",
KeyFile: "/cluster-signing-kubelet-serving/key-file",
},
KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kubelet-client/cert-file",
KeyFile: "/cluster-signing-kubelet-client/key-file",
},
KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
},
LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-legacy-unknown/cert-file",
KeyFile: "/cluster-signing-legacy-unknown/key-file",
},
}
halfASpecified := csrsigningconfig.CSRSigningControllerConfiguration{
ClusterSigningCertFile: "/cluster-signing-cert",
ClusterSigningKeyFile: "/cluster-signing-key",
ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kubelet-serving/cert-file",
KeyFile: "/cluster-signing-kubelet-serving/key-file",
},
KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kubelet-client/cert-file",
KeyFile: "/cluster-signing-kubelet-client/key-file",
},
}
halfBSpecified := csrsigningconfig.CSRSigningControllerConfiguration{
ClusterSigningCertFile: "/cluster-signing-cert",
ClusterSigningKeyFile: "/cluster-signing-key",
ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
},
LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-legacy-unknown/cert-file",
KeyFile: "/cluster-signing-legacy-unknown/key-file",
},
}
tests := []struct {
name string
config csrsigningconfig.CSRSigningControllerConfiguration
specifiedFn func(config csrsigningconfig.CSRSigningControllerConfiguration) bool
expectedSpecified bool
filesFn func(config csrsigningconfig.CSRSigningControllerConfiguration) (string, string)
expectedCert string
expectedKey string
}{
{
name: "allConfig-KubeletServingSignerFilesSpecified",
config: allConfig,
specifiedFn: areKubeletServingSignerFilesSpecified,
expectedSpecified: true,
filesFn: getKubeletServingSignerFiles,
expectedCert: "/cluster-signing-kubelet-serving/cert-file",
expectedKey: "/cluster-signing-kubelet-serving/key-file",
},
{
name: "defaultOnly-KubeletServingSignerFilesSpecified",
config: defaultOnly,
specifiedFn: areKubeletServingSignerFilesSpecified,
expectedSpecified: false,
filesFn: getKubeletServingSignerFiles,
expectedCert: "/cluster-signing-cert",
expectedKey: "/cluster-signing-key",
},
{
name: "specifiedOnly-KubeletServingSignerFilesSpecified",
config: specifiedOnly,
specifiedFn: areKubeletServingSignerFilesSpecified,
expectedSpecified: true,
filesFn: getKubeletServingSignerFiles,
expectedCert: "/cluster-signing-kubelet-serving/cert-file",
expectedKey: "/cluster-signing-kubelet-serving/key-file",
},
{
name: "halfASpecified-KubeletServingSignerFilesSpecified",
config: halfASpecified,
specifiedFn: areKubeletServingSignerFilesSpecified,
expectedSpecified: true,
filesFn: getKubeletServingSignerFiles,
expectedCert: "/cluster-signing-kubelet-serving/cert-file",
expectedKey: "/cluster-signing-kubelet-serving/key-file",
},
{
name: "halfBSpecified-KubeletServingSignerFilesSpecified",
config: halfBSpecified,
specifiedFn: areKubeletServingSignerFilesSpecified,
expectedSpecified: false,
filesFn: getKubeletServingSignerFiles,
expectedCert: "",
expectedKey: "",
},
{
name: "allConfig-KubeletClientSignerFiles",
config: allConfig,
specifiedFn: areKubeletClientSignerFilesSpecified,
expectedSpecified: true,
filesFn: getKubeletClientSignerFiles,
expectedCert: "/cluster-signing-kubelet-client/cert-file",
expectedKey: "/cluster-signing-kubelet-client/key-file",
},
{
name: "defaultOnly-KubeletClientSignerFiles",
config: defaultOnly,
specifiedFn: areKubeletClientSignerFilesSpecified,
expectedSpecified: false,
filesFn: getKubeletClientSignerFiles,
expectedCert: "/cluster-signing-cert",
expectedKey: "/cluster-signing-key",
},
{
name: "specifiedOnly-KubeletClientSignerFiles",
config: specifiedOnly,
specifiedFn: areKubeletClientSignerFilesSpecified,
expectedSpecified: true,
filesFn: getKubeletClientSignerFiles,
expectedCert: "/cluster-signing-kubelet-client/cert-file",
expectedKey: "/cluster-signing-kubelet-client/key-file",
},
{
name: "halfASpecified-KubeletClientSignerFiles",
config: halfASpecified,
specifiedFn: areKubeletClientSignerFilesSpecified,
expectedSpecified: true,
filesFn: getKubeletClientSignerFiles,
expectedCert: "/cluster-signing-kubelet-client/cert-file",
expectedKey: "/cluster-signing-kubelet-client/key-file",
},
{
name: "halfBSpecified-KubeletClientSignerFiles",
config: halfBSpecified,
specifiedFn: areKubeletClientSignerFilesSpecified,
expectedSpecified: false,
filesFn: getKubeletClientSignerFiles,
expectedCert: "",
expectedKey: "",
},
{
name: "allConfig-KubeletClientSignerFiles",
config: allConfig,
specifiedFn: areKubeAPIServerClientSignerFilesSpecified,
expectedSpecified: true,
filesFn: getKubeAPIServerClientSignerFiles,
expectedCert: "/cluster-signing-kube-apiserver-client/cert-file",
expectedKey: "/cluster-signing-kube-apiserver-client/key-file",
},
{
name: "defaultOnly-KubeletClientSignerFiles",
config: defaultOnly,
specifiedFn: areKubeAPIServerClientSignerFilesSpecified,
expectedSpecified: false,
filesFn: getKubeAPIServerClientSignerFiles,
expectedCert: "/cluster-signing-cert",
expectedKey: "/cluster-signing-key",
},
{
name: "specifiedOnly-KubeletClientSignerFiles",
config: specifiedOnly,
specifiedFn: areKubeAPIServerClientSignerFilesSpecified,
expectedSpecified: true,
filesFn: getKubeAPIServerClientSignerFiles,
expectedCert: "/cluster-signing-kube-apiserver-client/cert-file",
expectedKey: "/cluster-signing-kube-apiserver-client/key-file",
},
{
name: "halfASpecified-KubeletClientSignerFiles",
config: halfASpecified,
specifiedFn: areKubeAPIServerClientSignerFilesSpecified,
expectedSpecified: false,
filesFn: getKubeAPIServerClientSignerFiles,
expectedCert: "",
expectedKey: "",
},
{
name: "halfBSpecified-KubeletClientSignerFiles",
config: halfBSpecified,
specifiedFn: areKubeAPIServerClientSignerFilesSpecified,
expectedSpecified: true,
filesFn: getKubeAPIServerClientSignerFiles,
expectedCert: "/cluster-signing-kube-apiserver-client/cert-file",
expectedKey: "/cluster-signing-kube-apiserver-client/key-file",
},
{
name: "allConfig-LegacyUnknownSignerFiles",
config: allConfig,
specifiedFn: areLegacyUnknownSignerFilesSpecified,
expectedSpecified: true,
filesFn: getLegacyUnknownSignerFiles,
expectedCert: "/cluster-signing-legacy-unknown/cert-file",
expectedKey: "/cluster-signing-legacy-unknown/key-file",
},
{
name: "defaultOnly-LegacyUnknownSignerFiles",
config: defaultOnly,
specifiedFn: areLegacyUnknownSignerFilesSpecified,
expectedSpecified: false,
filesFn: getLegacyUnknownSignerFiles,
expectedCert: "/cluster-signing-cert",
expectedKey: "/cluster-signing-key",
},
{
name: "specifiedOnly-LegacyUnknownSignerFiles",
config: specifiedOnly,
specifiedFn: areLegacyUnknownSignerFilesSpecified,
expectedSpecified: true,
filesFn: getLegacyUnknownSignerFiles,
expectedCert: "/cluster-signing-legacy-unknown/cert-file",
expectedKey: "/cluster-signing-legacy-unknown/key-file",
},
{
name: "halfASpecified-LegacyUnknownSignerFiles",
config: halfASpecified,
specifiedFn: areLegacyUnknownSignerFilesSpecified,
expectedSpecified: false,
filesFn: getLegacyUnknownSignerFiles,
expectedCert: "",
expectedKey: "",
},
{
name: "halfBSpecified-LegacyUnknownSignerFiles",
config: halfBSpecified,
specifiedFn: areLegacyUnknownSignerFilesSpecified,
expectedSpecified: true,
filesFn: getLegacyUnknownSignerFiles,
expectedCert: "/cluster-signing-legacy-unknown/cert-file",
expectedKey: "/cluster-signing-legacy-unknown/key-file",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actualSpecified := test.specifiedFn(test.config)
if actualSpecified != test.expectedSpecified {
t.Error(actualSpecified)
}
actualCert, actualKey := test.filesFn(test.config)
if actualCert != test.expectedCert {
t.Error(actualCert)
}
if actualKey != test.expectedKey {
t.Error(actualKey)
}
})
}
}

View File

@ -17,21 +17,13 @@ limitations under the License.
package options
import (
"fmt"
"github.com/spf13/pflag"
csrsigningconfig "k8s.io/kubernetes/pkg/controller/certificates/signer/config"
)
const (
// These defaults are deprecated and exported so that we can warn if
// they are being used.
// DefaultClusterSigningCertFile is deprecated. Do not use.
DefaultClusterSigningCertFile = "/etc/kubernetes/ca/ca.pem"
// DefaultClusterSigningKeyFile is deprecated. Do not use.
DefaultClusterSigningKeyFile = "/etc/kubernetes/ca/ca.key"
)
// CSRSigningControllerOptions holds the CSRSigningController options.
type CSRSigningControllerOptions struct {
*csrsigningconfig.CSRSigningControllerConfiguration
@ -43,8 +35,16 @@ func (o *CSRSigningControllerOptions) AddFlags(fs *pflag.FlagSet) {
return
}
fs.StringVar(&o.ClusterSigningCertFile, "cluster-signing-cert-file", o.ClusterSigningCertFile, "Filename containing a PEM-encoded X509 CA certificate used to issue cluster-scoped certificates")
fs.StringVar(&o.ClusterSigningKeyFile, "cluster-signing-key-file", o.ClusterSigningKeyFile, "Filename containing a PEM-encoded RSA or ECDSA private key used to sign cluster-scoped certificates")
fs.StringVar(&o.ClusterSigningCertFile, "cluster-signing-cert-file", o.ClusterSigningCertFile, "Filename containing a PEM-encoded X509 CA certificate used to issue cluster-scoped certificates. If specified, no more specific --cluster-signing-* flag may be specified.")
fs.StringVar(&o.ClusterSigningKeyFile, "cluster-signing-key-file", o.ClusterSigningKeyFile, "Filename containing a PEM-encoded RSA or ECDSA private key used to sign cluster-scoped certificates. If specified, no more specific --cluster-signing-* flag may be specified.")
fs.StringVar(&o.KubeletServingSignerConfiguration.CertFile, "cluster-signing-kubelet-serving-cert-file", o.KubeletServingSignerConfiguration.CertFile, "Filename containing a PEM-encoded X509 CA certificate used to issue certificates for the kubernetes.io/kubelet-serving signer. If specified, --cluster-signing-{cert,key}-file must not be set.")
fs.StringVar(&o.KubeletServingSignerConfiguration.KeyFile, "cluster-signing-kubelet-serving-key-file", o.KubeletServingSignerConfiguration.KeyFile, "Filename containing a PEM-encoded RSA or ECDSA private key used to sign certificates for the kubernetes.io/kubelet-serving signer. If specified, --cluster-signing-{cert,key}-file must not be set.")
fs.StringVar(&o.KubeletClientSignerConfiguration.CertFile, "cluster-signing-kubelet-client-cert-file", o.KubeletClientSignerConfiguration.CertFile, "Filename containing a PEM-encoded X509 CA certificate used to issue certificates for the kubernetes.io/kube-apiserver-client-kubelet signer. If specified, --cluster-signing-{cert,key}-file must not be set.")
fs.StringVar(&o.KubeletClientSignerConfiguration.KeyFile, "cluster-signing-kubelet-client-key-file", o.KubeletClientSignerConfiguration.KeyFile, "Filename containing a PEM-encoded RSA or ECDSA private key used to sign certificates for the kubernetes.io/kube-apiserver-client-kubelet signer. If specified, --cluster-signing-{cert,key}-file must not be set.")
fs.StringVar(&o.KubeAPIServerClientSignerConfiguration.CertFile, "cluster-signing-kube-apiserver-client-cert-file", o.KubeAPIServerClientSignerConfiguration.CertFile, "Filename containing a PEM-encoded X509 CA certificate used to issue certificates for the kubernetes.io/kube-apiserver-client signer. If specified, --cluster-signing-{cert,key}-file must not be set.")
fs.StringVar(&o.KubeAPIServerClientSignerConfiguration.KeyFile, "cluster-signing-kube-apiserver-client-key-file", o.KubeAPIServerClientSignerConfiguration.KeyFile, "Filename containing a PEM-encoded RSA or ECDSA private key used to sign certificates for the kubernetes.io/kube-apiserver-client signer. If specified, --cluster-signing-{cert,key}-file must not be set.")
fs.StringVar(&o.LegacyUnknownSignerConfiguration.CertFile, "cluster-signing-legacy-unknown-cert-file", o.LegacyUnknownSignerConfiguration.CertFile, "Filename containing a PEM-encoded X509 CA certificate used to issue certificates for the kubernetes.io/legacy-unknown signer. If specified, --cluster-signing-{cert,key}-file must not be set.")
fs.StringVar(&o.LegacyUnknownSignerConfiguration.KeyFile, "cluster-signing-legacy-unknown-key-file", o.LegacyUnknownSignerConfiguration.KeyFile, "Filename containing a PEM-encoded RSA or ECDSA private key used to sign certificates for the kubernetes.io/legacy-unknown signer. If specified, --cluster-signing-{cert,key}-file must not be set.")
fs.DurationVar(&o.ClusterSigningDuration.Duration, "cluster-signing-duration", o.ClusterSigningDuration.Duration, "The length of duration signed certificates will be given.")
fs.DurationVar(&o.ClusterSigningDuration.Duration, "experimental-cluster-signing-duration", o.ClusterSigningDuration.Duration, "The length of duration signed certificates will be given.")
fs.MarkDeprecated("experimental-cluster-signing-duration", "use --cluster-signing-duration")
@ -58,6 +58,10 @@ func (o *CSRSigningControllerOptions) ApplyTo(cfg *csrsigningconfig.CSRSigningCo
cfg.ClusterSigningCertFile = o.ClusterSigningCertFile
cfg.ClusterSigningKeyFile = o.ClusterSigningKeyFile
cfg.KubeletServingSignerConfiguration = o.KubeletServingSignerConfiguration
cfg.KubeletClientSignerConfiguration = o.KubeletClientSignerConfiguration
cfg.KubeAPIServerClientSignerConfiguration = o.KubeAPIServerClientSignerConfiguration
cfg.LegacyUnknownSignerConfiguration = o.LegacyUnknownSignerConfiguration
cfg.ClusterSigningDuration = o.ClusterSigningDuration
return nil
@ -70,5 +74,43 @@ func (o *CSRSigningControllerOptions) Validate() []error {
}
errs := []error{}
if err := csrSigningFilesValid(o.KubeletServingSignerConfiguration); err != nil {
errs = append(errs, fmt.Errorf("%q: %v", "cluster-signing-kubelet-serving", err))
}
if err := csrSigningFilesValid(o.KubeletClientSignerConfiguration); err != nil {
errs = append(errs, fmt.Errorf("%q: %v", "cluster-signing-kube-apiserver-client", err))
}
if err := csrSigningFilesValid(o.KubeAPIServerClientSignerConfiguration); err != nil {
errs = append(errs, fmt.Errorf("%q: %v", "cluster-signing-kube-apiserver", err))
}
if err := csrSigningFilesValid(o.LegacyUnknownSignerConfiguration); err != nil {
errs = append(errs, fmt.Errorf("%q: %v", "cluster-signing-legacy-unknown", err))
}
singleSigningFile := len(o.ClusterSigningCertFile) > 0 || len(o.ClusterSigningKeyFile) > 0
anySpecificFilesSet := len(o.KubeletServingSignerConfiguration.CertFile) > 0 || len(o.KubeletServingSignerConfiguration.KeyFile) > 0 ||
len(o.KubeletClientSignerConfiguration.CertFile) > 0 || len(o.KubeletClientSignerConfiguration.KeyFile) > 0 ||
len(o.KubeAPIServerClientSignerConfiguration.CertFile) > 0 || len(o.KubeAPIServerClientSignerConfiguration.KeyFile) > 0 ||
len(o.LegacyUnknownSignerConfiguration.CertFile) > 0 || len(o.LegacyUnknownSignerConfiguration.KeyFile) > 0
if singleSigningFile && anySpecificFilesSet {
errs = append(errs, fmt.Errorf("cannot specify --cluster-signing-{cert,key}-file and other --cluster-signing-*-file flags at the same time"))
}
return errs
}
// both must be specified or both must be empty
func csrSigningFilesValid(config csrsigningconfig.CSRSigningConfiguration) error {
switch {
case (len(config.CertFile) == 0) && (len(config.KeyFile) == 0):
return nil
case (len(config.CertFile) != 0) && (len(config.KeyFile) != 0):
return nil
case (len(config.CertFile) == 0) && (len(config.KeyFile) != 0):
return fmt.Errorf("cannot specify key without cert")
case (len(config.CertFile) != 0) && (len(config.KeyFile) == 0):
return fmt.Errorf("cannot specify cert without key")
}
return fmt.Errorf("math broke")
}

View File

@ -68,6 +68,14 @@ var args = []string{
"--cluster-name=k8s",
"--cluster-signing-cert-file=/cluster-signing-cert",
"--cluster-signing-key-file=/cluster-signing-key",
"--cluster-signing-kubelet-serving-cert-file=/cluster-signing-kubelet-serving/cert-file",
"--cluster-signing-kubelet-serving-key-file=/cluster-signing-kubelet-serving/key-file",
"--cluster-signing-kubelet-client-cert-file=/cluster-signing-kubelet-client/cert-file",
"--cluster-signing-kubelet-client-key-file=/cluster-signing-kubelet-client/key-file",
"--cluster-signing-kube-apiserver-client-cert-file=/cluster-signing-kube-apiserver-client/cert-file",
"--cluster-signing-kube-apiserver-client-key-file=/cluster-signing-kube-apiserver-client/key-file",
"--cluster-signing-legacy-unknown-cert-file=/cluster-signing-legacy-unknown/cert-file",
"--cluster-signing-legacy-unknown-key-file=/cluster-signing-legacy-unknown/key-file",
"--concurrent-deployment-syncs=10",
"--concurrent-statefulset-syncs=15",
"--concurrent-endpoint-syncs=10",
@ -216,6 +224,22 @@ func TestAddFlags(t *testing.T) {
ClusterSigningCertFile: "/cluster-signing-cert",
ClusterSigningKeyFile: "/cluster-signing-key",
ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kubelet-serving/cert-file",
KeyFile: "/cluster-signing-kubelet-serving/key-file",
},
KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kubelet-client/cert-file",
KeyFile: "/cluster-signing-kubelet-client/key-file",
},
KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
},
LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-legacy-unknown/cert-file",
KeyFile: "/cluster-signing-legacy-unknown/key-file",
},
},
},
DaemonSetController: &DaemonSetControllerOptions{
@ -461,6 +485,22 @@ func TestApplyTo(t *testing.T) {
ClusterSigningCertFile: "/cluster-signing-cert",
ClusterSigningKeyFile: "/cluster-signing-key",
ClusterSigningDuration: metav1.Duration{Duration: 10 * time.Hour},
KubeletServingSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kubelet-serving/cert-file",
KeyFile: "/cluster-signing-kubelet-serving/key-file",
},
KubeletClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kubelet-client/cert-file",
KeyFile: "/cluster-signing-kubelet-client/key-file",
},
KubeAPIServerClientSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-kube-apiserver-client/cert-file",
KeyFile: "/cluster-signing-kube-apiserver-client/key-file",
},
LegacyUnknownSignerConfiguration: csrsigningconfig.CSRSigningConfiguration{
CertFile: "/cluster-signing-legacy-unknown/cert-file",
KeyFile: "/cluster-signing-legacy-unknown/key-file",
},
},
DaemonSetController: daemonconfig.DaemonSetControllerConfiguration{
ConcurrentDaemonSetSyncs: 2,

View File

@ -28,7 +28,27 @@ type CSRSigningControllerConfiguration struct {
// clusterSigningCertFile is the filename containing a PEM-encoded
// RSA or ECDSA private key used to issue cluster-scoped certificates
ClusterSigningKeyFile string
// kubeletServingSignerConfiguration holds the certificate and key used to issue certificates for the kubernetes.io/kubelet-serving signer
KubeletServingSignerConfiguration CSRSigningConfiguration
// kubeletClientSignerConfiguration holds the certificate and key used to issue certificates for the kubernetes.io/kube-apiserver-client-kubelet
KubeletClientSignerConfiguration CSRSigningConfiguration
// kubeAPIServerClientSignerConfiguration holds the certificate and key used to issue certificates for the kubernetes.io/kube-apiserver-client
KubeAPIServerClientSignerConfiguration CSRSigningConfiguration
// legacyUnknownSignerConfiguration holds the certificate and key used to issue certificates for the kubernetes.io/legacy-unknown
LegacyUnknownSignerConfiguration CSRSigningConfiguration
// clusterSigningDuration is the length of duration signed certificates
// will be given.
ClusterSigningDuration metav1.Duration
}
// CSRSigningConfiguration holds information about a particular CSR signer
type CSRSigningConfiguration struct {
// certFile is the filename containing a PEM-encoded
// X509 CA certificate used to issue certificates
CertFile string
// keyFile is the filename containing a PEM-encoded
// RSA or ECDSA private key used to issue certificates
KeyFile string
}

View File

@ -34,12 +34,6 @@ import (
// run it in your wrapper struct of this type in its `SetDefaults_` method.
func RecommendedDefaultCSRSigningControllerConfiguration(obj *kubectrlmgrconfigv1alpha1.CSRSigningControllerConfiguration) {
zero := metav1.Duration{}
if obj.ClusterSigningCertFile == "" {
obj.ClusterSigningCertFile = "/etc/kubernetes/ca/ca.pem"
}
if obj.ClusterSigningKeyFile == "" {
obj.ClusterSigningKeyFile = "/etc/kubernetes/ca/ca.key"
}
if obj.ClusterSigningDuration == zero {
obj.ClusterSigningDuration = metav1.Duration{Duration: 365 * 24 * time.Hour}
}

View File

@ -243,11 +243,31 @@ type CSRSigningControllerConfiguration struct {
// clusterSigningCertFile is the filename containing a PEM-encoded
// RSA or ECDSA private key used to issue cluster-scoped certificates
ClusterSigningKeyFile string
// kubeletServingSignerConfiguration holds the certificate and key used to issue certificates for the kubernetes.io/kubelet-serving signer
KubeletServingSignerConfiguration CSRSigningConfiguration
// kubeletClientSignerConfiguration holds the certificate and key used to issue certificates for the kubernetes.io/kube-apiserver-client-kubelet
KubeletClientSignerConfiguration CSRSigningConfiguration
// kubeAPIServerClientSignerConfiguration holds the certificate and key used to issue certificates for the kubernetes.io/kube-apiserver-client
KubeAPIServerClientSignerConfiguration CSRSigningConfiguration
// legacyUnknownSignerConfiguration holds the certificate and key used to issue certificates for the kubernetes.io/legacy-unknown
LegacyUnknownSignerConfiguration CSRSigningConfiguration
// clusterSigningDuration is the length of duration signed certificates
// will be given.
ClusterSigningDuration metav1.Duration
}
// CSRSigningConfiguration holds information about a particular CSR signer
type CSRSigningConfiguration struct {
// certFile is the filename containing a PEM-encoded
// X509 CA certificate used to issue certificates
CertFile string
// keyFile is the filename containing a PEM-encoded
// RSA or ECDSA private key used to issue certificates
KeyFile string
}
// DaemonSetControllerConfiguration contains elements describing DaemonSetController.
type DaemonSetControllerConfiguration struct {
// concurrentDaemonSetSyncs is the number of daemonset objects that are