Avoid generating a CA keypair on-demand

Instead we must explicitly create it; this avoids races where we are
reading the private key and creating CA certs.

Issue #3875
This commit is contained in:
Justin Santa Barbara 2017-11-25 17:19:40 -05:00
parent 875b41627d
commit e3c7f03aaa
4 changed files with 62 additions and 14 deletions

View File

@ -62,7 +62,8 @@ func NewClientsetCAStore(cluster *kops.Cluster, clientset kopsinternalversion.Ko
return c return c
} }
// readCAKeypairs retrieves the CA keypair, generating a new keypair if not found // readCAKeypairs retrieves the CA keypair.
// (No longer generates a keypair if not found.)
func (c *ClientsetCAStore) readCAKeypairs(id string) (*keyset, error) { func (c *ClientsetCAStore) readCAKeypairs(id string) (*keyset, error) {
c.mutex.Lock() c.mutex.Lock()
defer c.mutex.Unlock() defer c.mutex.Unlock()
@ -78,14 +79,9 @@ func (c *ClientsetCAStore) readCAKeypairs(id string) (*keyset, error) {
} }
if keyset == nil { if keyset == nil {
keyset, err = c.generateCACertificate(id) return nil, nil
if err != nil {
return nil, err
}
} }
c.cachedCaKeysets[id] = keyset c.cachedCaKeysets[id] = keyset
return keyset, nil return keyset, nil
} }

View File

@ -1,4 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
@ -27,3 +27,12 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
], ],
) )
go_test(
name = "go_default_test",
size = "small",
srcs = ["keypair_test.go"],
importpath = "k8s.io/kops/upup/pkg/fi/fitasks",
library = ":go_default_library",
deps = ["//upup/pkg/fi:go_default_library"],
)

View File

@ -0,0 +1,44 @@
/*
Copyright 2017 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 fitasks
import (
"k8s.io/kops/upup/pkg/fi"
"strings"
"testing"
)
func TestKeypairDeps(t *testing.T) {
ca := &Keypair{}
cert := &Keypair{
Signer: ca,
}
tasks := make(map[string]fi.Task)
tasks["ca"] = ca
tasks["cert"] = cert
deps := fi.FindTaskDependencies(tasks)
if strings.Join(deps["ca"], ",") != "" {
t.Errorf("unexpected dependencies for ca: %v", deps["ca"])
}
if strings.Join(deps["cert"], ",") != "ca" {
t.Errorf("unexpected dependencies for cert: %v", deps["cert"])
}
}

View File

@ -68,7 +68,7 @@ func (s *VFSCAStore) VFSPath() vfs.Path {
return s.basedir return s.basedir
} }
// Retrieves the CA keypair, generating a new keypair if not found // Retrieves the CA keypair. No longer generates keypairs if not found.
func (s *VFSCAStore) readCAKeypairs(id string) (*certificates, *privateKeys, error) { func (s *VFSCAStore) readCAKeypairs(id string) (*certificates, *privateKeys, error) {
s.mutex.Lock() s.mutex.Lock()
defer s.mutex.Unlock() defer s.mutex.Unlock()
@ -98,16 +98,15 @@ func (s *VFSCAStore) readCAKeypairs(id string) (*certificates, *privateKeys, err
} }
if caPrivateKeys == nil { if caPrivateKeys == nil {
caCertificates, caPrivateKeys, err = s.generateCACertificate(id) // We no longer generate CA certificates automatically - too race-prone
if err != nil { return caCertificates, caPrivateKeys, nil
return nil, nil, err
}
} }
cached = &cachedEntry{certificates: caCertificates, privateKeys: caPrivateKeys} cached = &cachedEntry{certificates: caCertificates, privateKeys: caPrivateKeys}
s.cachedCAs[id] = cached s.cachedCAs[id] = cached
return cached.certificates, cached.privateKeys, nil return cached.certificates, cached.privateKeys, nil
} }
func BuildCAX509Template() *x509.Certificate { func BuildCAX509Template() *x509.Certificate {