提交 cdae55ef 编写于 作者: J Jordan Liggitt 提交者: Sebastian Florek

Auto-generate certs in-memory (#2795)

上级 2c7e17ea
......@@ -14,6 +14,8 @@
package api
import "crypto/tls"
const (
// Certificate file names that will be generated by Dashboard
DashboardCertName = "dashboard.crt"
......@@ -23,8 +25,8 @@ const (
// Manager is responsible for generating and storing self-signed certificates that can be used by Dashboard
// to serve over HTTPS.
type Manager interface {
// GenerateCertificates generates self-signed certificates.
GenerateCertificates()
// GetCertificates loads existing certificates or generates self-signed certificates.
GetCertificates() (tls.Certificate, error)
}
// Creator is responsible for preparing and generating certificates.
......@@ -35,6 +37,8 @@ type Creator interface {
GenerateCertificate(key interface{}) []byte
// StoreCertificates saves certificates in a given path
StoreCertificates(path string, key interface{}, certBytes []byte)
// KeyCertPEMBytes converts the key and cert to PEM format
KeyCertPEMBytes(key interface{}, certBytes []byte) (keyPEM []byte, certPEM []byte, err error)
// GetKeyFileName returns certificate key file name
GetKeyFileName() string
// GetCertFileName returns certificate file name
......
......@@ -21,6 +21,7 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"io/ioutil"
"log"
"math/big"
"net"
......@@ -76,26 +77,26 @@ func (self *ecdsaCreator) GenerateCertificate(key interface{}) []byte {
// StoreCertificates implements certificate Creator interface. See Creator for more information.
func (self *ecdsaCreator) StoreCertificates(path string, key interface{}, certBytes []byte) {
ecdsaKey := self.getKey(key)
certOut, err := os.Create(path + string(os.PathSeparator) + self.GetCertFileName())
keyPEM, certPEM, err := self.KeyCertPEMBytes(key, certBytes)
if err != nil {
log.Fatalf("[ECDSAManager] Failed to marshal cert/key pair: %v", err)
}
if err := ioutil.WriteFile(path+string(os.PathSeparator)+self.GetCertFileName(), certPEM, os.FileMode(0644)); err != nil {
log.Fatalf("[ECDSAManager] Failed to open %s for writing: %s", self.GetCertFileName(), err)
}
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
certOut.Close()
keyOut, err := os.OpenFile(path+string(os.PathSeparator)+self.GetKeyFileName(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
if err := ioutil.WriteFile(path+string(os.PathSeparator)+self.GetKeyFileName(), keyPEM, os.FileMode(0600)); err != nil {
log.Fatalf("[ECDSAManager] Failed to open %s for writing: %s", self.GetKeyFileName(), err)
}
}
marshaledKey, err := x509.MarshalECPrivateKey(ecdsaKey)
func (self *ecdsaCreator) KeyCertPEMBytes(key interface{}, certBytes []byte) ([]byte, []byte, error) {
marshaledKey, err := x509.MarshalECPrivateKey(self.getKey(key))
if err != nil {
log.Fatalf("[ECDSAManager] Unable to marshal %s: %v", self.GetKeyFileName(), err)
return nil, nil, err
}
pem.Encode(keyOut, &pem.Block{Type: "EC PRIVATE KEY", Bytes: marshaledKey})
keyOut.Close()
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: marshaledKey})
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
return keyPEM, certPEM, nil
}
// GetKeyFileName implements certificate Creator interface. See Creator for more information.
......
......@@ -15,6 +15,7 @@
package cert
import (
"crypto/tls"
"log"
"os"
......@@ -28,16 +29,23 @@ type Manager struct {
}
// GenerateCertificates implements Manager interface. See Manager for more information.
func (self *Manager) GenerateCertificates() {
func (self *Manager) GetCertificates() (tls.Certificate, error) {
if self.keyFileExists() && self.certFileExists() {
log.Println("Certificates already exist. Skipping.")
return
log.Println("Certificates already exist. Returning.")
return tls.LoadX509KeyPair(
self.path(self.creator.GetCertFileName()),
self.path(self.creator.GetKeyFileName()),
)
}
key := self.creator.GenerateKey()
cert := self.creator.GenerateCertificate(key)
self.creator.StoreCertificates(self.certDir, key, cert)
log.Println("Successfuly created and stored certificates")
log.Println("Successfully created certificates")
keyPEM, certPEM, err := self.creator.KeyCertPEMBytes(key, cert)
if err != nil {
return tls.Certificate{}, err
}
return tls.X509KeyPair(certPEM, keyPEM)
}
func (self *Manager) keyFileExists() bool {
......
......@@ -16,6 +16,7 @@ package main
import (
"crypto/elliptic"
"crypto/tls"
"flag"
"fmt"
"log"
......@@ -121,11 +122,24 @@ func main() {
handleFatalInitError(err)
}
var servingCerts []tls.Certificate
if args.Holder.GetAutoGenerateCertificates() {
log.Println("Auto-generating certificates")
certCreator := ecdsa.NewECDSACreator(args.Holder.GetKeyFile(), args.Holder.GetCertFile(), elliptic.P256())
certManager := cert.NewCertManager(certCreator, args.Holder.GetDefaultCertDir())
certManager.GenerateCertificates()
servingCert, err := certManager.GetCertificates()
if err != nil {
handleFatalInitError(err)
}
servingCerts = []tls.Certificate{servingCert}
} else if args.Holder.GetCertFile() != "" && args.Holder.GetKeyFile() != "" {
certFilePath := args.Holder.GetDefaultCertDir() + string(os.PathSeparator) + args.Holder.GetCertFile()
keyFilePath := args.Holder.GetDefaultCertDir() + string(os.PathSeparator) + args.Holder.GetKeyFile()
servingCert, err := tls.LoadX509KeyPair(certFilePath, keyFilePath)
if err != nil {
handleFatalInitError(err)
}
servingCerts = []tls.Certificate{servingCert}
}
// Run a HTTP server that serves static public files from './public' and handles API calls.
......@@ -138,12 +152,15 @@ func main() {
http.Handle("/metrics", prometheus.Handler())
// Listen for http or https
if args.Holder.GetCertFile() != "" && args.Holder.GetKeyFile() != "" {
certFilePath := args.Holder.GetDefaultCertDir() + string(os.PathSeparator) + args.Holder.GetCertFile()
keyFilePath := args.Holder.GetDefaultCertDir() + string(os.PathSeparator) + args.Holder.GetKeyFile()
if servingCerts != nil {
log.Printf("Serving securely on HTTPS port: %d", args.Holder.GetPort())
secureAddr := fmt.Sprintf("%s:%d", args.Holder.GetBindAddress(), args.Holder.GetPort())
go func() { log.Fatal(http.ListenAndServeTLS(secureAddr, certFilePath, keyFilePath, nil)) }()
server := &http.Server{
Addr: secureAddr,
Handler: http.DefaultServeMux,
TLSConfig: &tls.Config{Certificates: servingCerts},
}
go func() { log.Fatal(server.ListenAndServeTLS("", "")) }()
} else {
log.Printf("Serving insecurely on HTTP port: %d", args.Holder.GetInsecurePort())
addr := fmt.Sprintf("%s:%d", args.Holder.GetInsecureBindAddress(), args.Holder.GetInsecurePort())
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册