diff --git a/cmd/kube-apiserver/apiserver.go b/cmd/kube-apiserver/apiserver.go index ece895b736d..131846e3c7d 100644 --- a/cmd/kube-apiserver/apiserver.go +++ b/cmd/kube-apiserver/apiserver.go @@ -58,8 +58,11 @@ var ( "The port from which to serve read-only resources. If 0, don't serve on a "+ "read-only address. It is assumed that firewall rules are set up such that "+ "this port is not reachable from outside of the cluster.") - securePort = flag.Int("secure_port", 0, "The port from which to serve HTTPS with authentication and authorization. If 0, don't serve HTTPS ") - tlsCertFile = flag.String("tls_cert_file", "", "File containing x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert).") + securePort = flag.Int("secure_port", 8443, "The port from which to serve HTTPS with authentication and authorization. If 0, don't serve HTTPS ") + tlsCertFile = flag.String("tls_cert_file", "", ""+ + "File containing x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert). "+ + "If HTTPS serving is enabled, and --tls_cert_file and --tls_private_key_file are not provided, "+ + "a self-signed certificate and key are generated for the public address and saved to /var/run/kubernetes.") tlsPrivateKeyFile = flag.String("tls_private_key_file", "", "File containing x509 private key matching --tls_cert_file.") apiPrefix = flag.String("api_prefix", "/api", "The prefix for API requests on the server. Default '/api'.") storageVersion = flag.String("storage_version", "", "The version to store resources with. Defaults to server preferred") @@ -236,6 +239,15 @@ func main() { go func() { defer util.HandleCrash() for { + if *tlsCertFile == "" && *tlsPrivateKeyFile == "" { + *tlsCertFile = "/var/run/kubernetes/apiserver.crt" + *tlsPrivateKeyFile = "/var/run/kubernetes/apiserver.key" + if err := util.GenerateSelfSignedCert(config.PublicAddress, *tlsCertFile, *tlsPrivateKeyFile); err != nil { + glog.Errorf("Unable to generate self signed cert: %v", err) + } else { + glog.Infof("Using self-signed cert (%s, %s)", *tlsCertFile, *tlsPrivateKeyFile) + } + } if err := secureServer.ListenAndServeTLS(*tlsCertFile, *tlsPrivateKeyFile); err != nil { glog.Errorf("Unable to listen for secure (%v); will try again.", err) } diff --git a/pkg/util/crypto.go b/pkg/util/crypto.go new file mode 100644 index 00000000000..87a485a9917 --- /dev/null +++ b/pkg/util/crypto.go @@ -0,0 +1,99 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +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 util + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "io/ioutil" + "math/big" + "net" + "os" + "path/filepath" + "time" +) + +// GenerateSelfSignedCert creates a self-signed certificate and key for the given host. +// Host may be an IP or a DNS name +// The certificate will be created with file mode 0644. The key will be created with file mode 0600. +// If the certificate or key files already exist, they will be overwritten. +// Any parent directories of the certPath or keyPath will be created as needed with file mode 0755. +func GenerateSelfSignedCert(host, certPath, keyPath string) error { + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return err + } + + template := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()), + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour * 24 * 365), + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + if ip := net.ParseIP(host); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, host) + } + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + if err != nil { + return err + } + + // Generate cert + certBuffer := bytes.Buffer{} + if err := pem.Encode(&certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { + return err + } + + // Generate key + keyBuffer := bytes.Buffer{} + if err := pem.Encode(&keyBuffer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil { + return err + } + + // Write cert + if err := os.MkdirAll(filepath.Dir(certPath), os.FileMode(0755)); err != nil { + return err + } + if err := ioutil.WriteFile(certPath, certBuffer.Bytes(), os.FileMode(0644)); err != nil { + return err + } + + // Write key + if err := os.MkdirAll(filepath.Dir(keyPath), os.FileMode(0755)); err != nil { + return err + } + if err := ioutil.WriteFile(keyPath, keyBuffer.Bytes(), os.FileMode(0600)); err != nil { + return err + } + + return nil +}