mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Server: Automatically generate a self-signed TLS cert if needed (#78243)
generate a self-signed cert when running in https or http2 mode without a provided cert
This commit is contained in:
parent
7e2aad1d01
commit
647f576359
@ -1,10 +1,17 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -12,6 +19,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
@ -429,7 +437,7 @@ func (hs *HTTPServer) Run(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
case setting.HTTP2Scheme, setting.HTTPSScheme:
|
||||
if err := hs.httpSrv.ServeTLS(listener, hs.Cfg.CertFile, hs.Cfg.KeyFile); err != nil {
|
||||
if err := hs.httpSrv.ServeTLS(listener, "", ""); err != nil {
|
||||
if errors.Is(err, http.ErrServerClosed) {
|
||||
hs.log.Debug("server was shutdown gracefully")
|
||||
return nil
|
||||
@ -482,21 +490,93 @@ func (hs *HTTPServer) getListener() (net.Listener, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) configureHttps() error {
|
||||
func (hs *HTTPServer) selfSignedCert() ([]tls.Certificate, error) {
|
||||
template := &x509.Certificate{
|
||||
IsCA: true,
|
||||
BasicConstraintsValid: true,
|
||||
SubjectKeyId: []byte{1},
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{
|
||||
CommonName: hs.Cfg.Domain,
|
||||
},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(1, 0, 0),
|
||||
// see http://golang.org/pkg/crypto/x509/#KeyUsage
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
|
||||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||
}
|
||||
|
||||
// generate private key
|
||||
privatekey, err := rsa.GenerateKey(rand.Reader, 4096)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating tls private key: %w", err)
|
||||
}
|
||||
|
||||
publickey := &privatekey.PublicKey
|
||||
|
||||
// create a self-signed certificate
|
||||
var parent = template
|
||||
certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, publickey, privatekey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating tls self-signed certificate: %w", err)
|
||||
}
|
||||
|
||||
// encode certificate and private key to PEM
|
||||
certPEM := new(bytes.Buffer)
|
||||
_ = pem.Encode(certPEM, &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: certBytes,
|
||||
})
|
||||
|
||||
certPrivKeyPEM := new(bytes.Buffer)
|
||||
_ = pem.Encode(certPrivKeyPEM, &pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(privatekey),
|
||||
})
|
||||
|
||||
// create tlsCertificate from generated certificate and private key
|
||||
tlsCert, err := tls.X509KeyPair(certPEM.Bytes(), certPrivKeyPEM.Bytes())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating tls self-signed certificate: %w", err)
|
||||
}
|
||||
|
||||
return []tls.Certificate{tlsCert}, nil
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) tlsCertificates() ([]tls.Certificate, error) {
|
||||
// if we don't have either a cert or key specified, generate a self-signed certificate
|
||||
if hs.Cfg.CertFile == "" && hs.Cfg.KeyFile == "" {
|
||||
return hs.selfSignedCert()
|
||||
}
|
||||
|
||||
if hs.Cfg.CertFile == "" {
|
||||
return errors.New("cert_file cannot be empty when using HTTPS")
|
||||
return nil, errors.New("cert_file cannot be empty when using HTTPS")
|
||||
}
|
||||
|
||||
if hs.Cfg.KeyFile == "" {
|
||||
return errors.New("cert_key cannot be empty when using HTTPS")
|
||||
return nil, errors.New("cert_key cannot be empty when using HTTPS")
|
||||
}
|
||||
|
||||
if _, err := os.Stat(hs.Cfg.CertFile); os.IsNotExist(err) {
|
||||
return fmt.Errorf(`cannot find SSL cert_file at %q`, hs.Cfg.CertFile)
|
||||
return nil, fmt.Errorf(`cannot find SSL cert_file at %q`, hs.Cfg.CertFile)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(hs.Cfg.KeyFile); os.IsNotExist(err) {
|
||||
return fmt.Errorf(`cannot find SSL key_file at %q`, hs.Cfg.KeyFile)
|
||||
return nil, fmt.Errorf(`cannot find SSL key_file at %q`, hs.Cfg.KeyFile)
|
||||
}
|
||||
|
||||
tlsCert, err := tls.LoadX509KeyPair(hs.Cfg.CertFile, hs.Cfg.KeyFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not load SSL certificate: %w", err)
|
||||
}
|
||||
|
||||
return []tls.Certificate{tlsCert}, nil
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) configureHttps() error {
|
||||
tlsCerts, err := hs.tlsCertificates()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
minTlsVersion, err := util.TlsNameToVersion(hs.Cfg.MinTLSVersion)
|
||||
@ -513,6 +593,7 @@ func (hs *HTTPServer) configureHttps() error {
|
||||
"configured ciphers", util.TlsCipherIdsToString(tlsCiphers))
|
||||
|
||||
tlsCfg := &tls.Config{
|
||||
Certificates: tlsCerts,
|
||||
MinVersion: minTlsVersion,
|
||||
CipherSuites: tlsCiphers,
|
||||
}
|
||||
@ -524,20 +605,9 @@ func (hs *HTTPServer) configureHttps() error {
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) configureHttp2() error {
|
||||
if hs.Cfg.CertFile == "" {
|
||||
return errors.New("cert_file cannot be empty when using HTTP2")
|
||||
}
|
||||
|
||||
if hs.Cfg.KeyFile == "" {
|
||||
return errors.New("cert_key cannot be empty when using HTTP2")
|
||||
}
|
||||
|
||||
if _, err := os.Stat(hs.Cfg.CertFile); os.IsNotExist(err) {
|
||||
return fmt.Errorf("cannot find SSL cert_file at %q", hs.Cfg.CertFile)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(hs.Cfg.KeyFile); os.IsNotExist(err) {
|
||||
return fmt.Errorf("cannot find SSL key_file at %q", hs.Cfg.KeyFile)
|
||||
tlsCerts, err := hs.tlsCertificates()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
minTlsVersion, err := util.TlsNameToVersion(hs.Cfg.MinTLSVersion)
|
||||
@ -551,6 +621,7 @@ func (hs *HTTPServer) configureHttp2() error {
|
||||
"configured ciphers", util.TlsCipherIdsToString(tlsCiphers))
|
||||
|
||||
tlsCfg := &tls.Config{
|
||||
Certificates: tlsCerts,
|
||||
MinVersion: minTlsVersion,
|
||||
CipherSuites: tlsCiphers,
|
||||
NextProtos: []string{"h2", "http/1.1"},
|
||||
|
Loading…
Reference in New Issue
Block a user