diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 2efaaf8a..f6d3ec36 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -392,207 +392,207 @@ }, { "ImportPath": "k8s.io/apimachinery/pkg/api/equality", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/api/errors", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/api/meta", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/api/resource", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/api/testing", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/api/testing/fuzzer", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/api/testing/roundtrip", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1beta1", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/conversion", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/fields", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/labels", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/schema", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/selection", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/types", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/cache", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/clock", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/diff", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/errors", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/framer", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/intstr", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/json", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/naming", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/net", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/runtime", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/sets", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/validation", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/validation/field", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/wait", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/util/yaml", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/version", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/pkg/watch", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect", - "Rev": "8dd74a0baf0dd7bdb3726e3fc9db6c59e03b0c45" + "Rev": "5e3c3f9281db3188d57785c1f6afe5eb504ede4f" }, { "ImportPath": "k8s.io/kube-openapi/pkg/util/proto", diff --git a/util/cert/cert.go b/util/cert/cert.go index fb7f5fac..0d6794bb 100644 --- a/util/cert/cert.go +++ b/util/cert/cert.go @@ -27,9 +27,12 @@ import ( "encoding/pem" "errors" "fmt" + "io/ioutil" "math" "math/big" "net" + "path" + "strings" "time" ) @@ -136,8 +139,38 @@ func MakeEllipticPrivateKeyPEM() ([]byte, error) { // GenerateSelfSignedCertKey creates a self-signed certificate and key for the given host. // Host may be an IP or a DNS name -// You may also specify additional subject alt names (either ip or dns names) for the certificate +// You may also specify additional subject alt names (either ip or dns names) for the certificate. func GenerateSelfSignedCertKey(host string, alternateIPs []net.IP, alternateDNS []string) ([]byte, []byte, error) { + return GenerateSelfSignedCertKeyWithFixtures(host, alternateIPs, alternateDNS, "") +} + +// GenerateSelfSignedCertKeyWithFixtures creates a self-signed certificate and key for the given host. +// Host may be an IP or a DNS name. You may also specify additional subject alt names (either ip or dns names) +// for the certificate. +// +// If fixtureDirectory is non-empty, it is a directory path which can contain pre-generated certs. The format is: +// _-_-.crt +// _-_-.key +// Certs/keys not existing in that directory are created. +func GenerateSelfSignedCertKeyWithFixtures(host string, alternateIPs []net.IP, alternateDNS []string, fixtureDirectory string) ([]byte, []byte, error) { + validFrom := time.Now().Add(-time.Hour) // valid an hour earlier to avoid flakes due to clock skew + maxAge := time.Hour * 24 * 365 // one year self-signed certs + + baseName := fmt.Sprintf("%s_%s_%s", host, strings.Join(ipsToStrings(alternateIPs), "-"), strings.Join(alternateDNS, "-")) + certFixturePath := path.Join(fixtureDirectory, baseName+".crt") + keyFixturePath := path.Join(fixtureDirectory, baseName+".key") + if len(fixtureDirectory) > 0 { + cert, err := ioutil.ReadFile(certFixturePath) + if err == nil { + key, err := ioutil.ReadFile(keyFixturePath) + if err == nil { + return cert, key, nil + } + return nil, nil, fmt.Errorf("cert %s can be read, but key %s cannot: %v", certFixturePath, keyFixturePath, err) + } + maxAge = 100 * time.Hour * 24 * 365 // 100 years fixtures + } + caKey, err := rsa.GenerateKey(cryptorand.Reader, 2048) if err != nil { return nil, nil, err @@ -148,8 +181,8 @@ func GenerateSelfSignedCertKey(host string, alternateIPs []net.IP, alternateDNS Subject: pkix.Name{ CommonName: fmt.Sprintf("%s-ca@%d", host, time.Now().Unix()), }, - NotBefore: time.Now(), - NotAfter: time.Now().Add(time.Hour * 24 * 365), + NotBefore: validFrom, + NotAfter: validFrom.Add(maxAge), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, BasicConstraintsValid: true, @@ -176,8 +209,8 @@ func GenerateSelfSignedCertKey(host string, alternateIPs []net.IP, alternateDNS Subject: pkix.Name{ CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()), }, - NotBefore: time.Now(), - NotAfter: time.Now().Add(time.Hour * 24 * 365), + NotBefore: validFrom, + NotAfter: validFrom.Add(maxAge), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, @@ -213,6 +246,15 @@ func GenerateSelfSignedCertKey(host string, alternateIPs []net.IP, alternateDNS return nil, nil, err } + if len(fixtureDirectory) > 0 { + if err := ioutil.WriteFile(certFixturePath, certBuffer.Bytes(), 0644); err != nil { + return nil, nil, fmt.Errorf("failed to write cert fixture to %s: %v", certFixturePath, err) + } + if err := ioutil.WriteFile(keyFixturePath, keyBuffer.Bytes(), 0644); err != nil { + return nil, nil, fmt.Errorf("failed to write key fixture to %s: %v", certFixturePath, err) + } + } + return certBuffer.Bytes(), keyBuffer.Bytes(), nil } @@ -243,3 +285,11 @@ func FormatCert(c *x509.Certificate) string { } return res } + +func ipsToStrings(ips []net.IP) []string { + ss := make([]string, 0, len(ips)) + for _, ip := range ips { + ss = append(ss, ip.String()) + } + return ss +}