Переглянути джерело

check (and gen if missing) certs on startup

Signed-off-by: Matthew R. Kasun <[email protected]>
Matthew R. Kasun 3 роки тому
батько
коміт
460d971b50
5 змінених файлів з 153 додано та 9 видалено
  1. 1 0
      go.mod
  2. 1 0
      go.sum
  3. 73 1
      main.go
  4. 2 2
      servercfg/serverconf.go
  5. 76 6
      tls/tls.go

+ 1 - 0
go.mod

@@ -32,6 +32,7 @@ require (
 )
 
 require (
+	filippo.io/edwards25519 v1.0.0-beta.3
 	github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534
 	github.com/guumaster/hostctl v1.1.2
 	github.com/kr/pretty v0.3.0

+ 1 - 0
go.sum

@@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 filippo.io/age v1.0.0-rc.3 h1:8JjuJ5ffGKDmC4SS0zoyQxZROZX75so768b7AjulKLw=
 filippo.io/age v1.0.0-rc.3/go.mod h1:UjINLBMeA60aGZkHCGsmDzKcaXoTTzpvrqQM+Vo3YHU=
+filippo.io/edwards25519 v1.0.0-beta.3 h1:WQxB0FH5NzrhciInJ30bgL3soLng3AbdI651yQuVlCs=
 filippo.io/edwards25519 v1.0.0-beta.3/go.mod h1:X+pm78QAUPtFLi1z9PYIlS/bdDnvbCOGKtZ+ACWEf7o=
 git.sr.ht/~lofi/lib v0.0.15 h1:Hii3gq4+RNWc1CSuTqJQOKSl7BpUPHeNrePRaLSxA6g=
 git.sr.ht/~lofi/lib v0.0.15/go.mod h1:73Uyg0sHjhOGMS9wybiSVkg8vDqJIZGLpOxdJArGo78=

+ 73 - 1
main.go

@@ -2,6 +2,9 @@ package main
 
 import (
 	"context"
+	"crypto/ed25519"
+	"crypto/x509"
+	"errors"
 	"flag"
 	"fmt"
 	"net"
@@ -25,6 +28,7 @@ import (
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/serverctl"
+	"github.com/gravitl/netmaker/tls"
 	"google.golang.org/grpc"
 )
 
@@ -38,7 +42,8 @@ func main() {
 	setupConfig(*absoluteConfigPath)
 	servercfg.SetVersion(version)
 	fmt.Println(models.RetrieveLogo()) // print the logo
-	initialize()                       // initial db and grpc server
+	initialize()
+	logger.Log(2, "inialization complete") // initial db and grpc server
 	setGarbageCollection()
 	defer database.CloseDB()
 	startControllers() // start the grpc or rest endpoints
@@ -117,6 +122,11 @@ func initialize() { // Client Mode Prereq Check
 			logger.FatalLog(err.Error())
 		}
 	}
+	if servercfg.GetServerName() == "" {
+		logger.FatalLog("Server Name not set")
+	}
+	logger.Log(2, "Checking certificates")
+	checkCertificates(servercfg.GetServerName())
 }
 
 func startControllers() {
@@ -235,3 +245,65 @@ func setGarbageCollection() {
 		debug.SetGCPercent(ncutils.DEFAULT_GC_PERCENT)
 	}
 }
+
+func checkCertificates(server string) {
+	var key *ed25519.PrivateKey
+	var ca *x509.Certificate
+	if _, err := os.Stat("/etc/netclient/root.pem"); errors.Is(err, os.ErrNotExist) {
+		logger.Log(2, "generating root CA")
+		key, ca, err = generateRootCA()
+		if err != nil {
+			logger.FatalLog("root-ca failure ", err.Error())
+		}
+	}
+	if _, err := os.Stat("/etc/netclient/" + server + "/server.pem"); errors.Is(err, os.ErrNotExist) {
+		logger.Log(2, "generating server certificate")
+		_, err := generateCertificate(server, key, ca)
+		if err != nil {
+			logger.FatalLog("server cert failure ", err.Error())
+		}
+	}
+}
+
+func generateRootCA() (*ed25519.PrivateKey, *x509.Certificate, error) {
+	key := tls.NewKey()
+	privateKey, err := key.Ed25519PrivateKey()
+	if err != nil {
+		return nil, nil, fmt.Errorf("private key %w", err)
+	}
+	name := tls.NewCName("Gravitl")
+	csr, err := tls.NewCSR(privateKey, name)
+	if err != nil {
+		return nil, nil, fmt.Errorf("csr %w", err)
+	}
+	ca, err := tls.SelfSignedCA(privateKey, csr, 365)
+	if err != nil {
+		return nil, nil, fmt.Errorf("self signed cert %w", err)
+	}
+	logger.Log(2, "Saving root key")
+	if err := tls.SaveKey("/etc/netmaker/", "root.key", privateKey); err != nil {
+		return nil, nil, fmt.Errorf("save key %w", err)
+	}
+	logger.Log(2, "Saving root ca")
+	if err := tls.SaveCert("/etc/netmaker/", "root.pem", ca); err != nil {
+		return nil, nil, fmt.Errorf("save root ca %w", err)
+	}
+	return &privateKey, ca, nil
+}
+
+func generateCertificate(server string, key *ed25519.PrivateKey, ca *x509.Certificate) (*x509.Certificate, error) {
+	name := tls.NewName(server, "", "Netmaker")
+	csr, err := tls.NewCSR(*key, name)
+	if err != nil {
+		return nil, fmt.Errorf("csr %w", err)
+	}
+	cert, err := tls.NewEndEntityCert(*key, csr, ca, 365)
+	if err != nil {
+		return nil, fmt.Errorf("cert %w", err)
+	}
+	logger.Log(2, "saving server cert")
+	if err := tls.SaveCert("/etc/netmaker/"+server+"/", "/server.pem", cert); err != nil {
+		return nil, fmt.Errorf("save cert %w", err)
+	}
+	return cert, nil
+}

+ 2 - 2
servercfg/serverconf.go

@@ -262,8 +262,8 @@ func GetMQPort() string {
 // GetServerName - gets FQDN of server
 func GetServerName() string {
 	name := ""
-	if os.Getenv("DOMAIN_NAME") != "" {
-		name = os.Getenv("DOMAIN_NAME")
+	if os.Getenv("SERVER_NAME") != "" {
+		name = os.Getenv("SERVER_NAME")
 	} else if config.Config.Server.ServerName != "" {
 		name = config.Config.Server.ServerName
 	}

+ 76 - 6
ssl/ssl.go → tls/tls.go

@@ -1,10 +1,11 @@
-package ssl
+package tls
 
 import (
 	"crypto/ed25519"
 	"crypto/rand"
 	"crypto/x509"
 	"crypto/x509/pkix"
+	"encoding/base64"
 	"encoding/pem"
 	"errors"
 	"fmt"
@@ -12,8 +13,71 @@ import (
 	"math/big"
 	"os"
 	"time"
+
+	"filippo.io/edwards25519"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+)
+
+type (
+	Key struct {
+		point *edwards25519.Point
+	}
 )
 
+// NewKey generates a new key.
+func NewKey() *Key {
+	seed := make([]byte, 64)
+	rand.Reader.Read(seed)
+	s := (&edwards25519.Scalar{}).SetUniformBytes(seed)
+	return &Key{(&edwards25519.Point{}).ScalarBaseMult(s)}
+}
+
+// Ed25519PrivateKey returns the private key in Edwards form used for EdDSA.
+func (n *Key) Ed25519PrivateKey() (ed25519.PrivateKey, error) {
+	if n.point == nil {
+		return ed25519.PrivateKey{}, errors.New("nil point")
+	}
+	if len(n.point.Bytes()) != ed25519.SeedSize {
+		return ed25519.PrivateKey{}, errors.New("incorrect seed size")
+	}
+	return ed25519.NewKeyFromSeed(n.point.Bytes()), nil
+}
+
+// Curve25519PrivateKey returns the private key in Montogomery form used for ECDH.
+func (n *Key) Curve25519PrivateKey() (wgtypes.Key, error) {
+	if n.point == nil {
+		return wgtypes.Key{}, errors.New("nil point")
+	}
+	if len(n.point.Bytes()) != ed25519.SeedSize {
+		return wgtypes.Key{}, errors.New("incorrect seed size")
+	}
+	return wgtypes.ParseKey(base64.StdEncoding.EncodeToString(n.point.BytesMontgomery()))
+}
+
+// Save : saves the private key to path.
+func (n *Key) Save(path string) error {
+	f, err := os.Create(path)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	f.Write(n.point.Bytes())
+	return nil
+}
+
+// Reads the private key from path.
+func ReadFrom(path string) (*Key, error) {
+	key, err := os.ReadFile(path)
+	if err != nil {
+		return nil, err
+	}
+	point, err := (&edwards25519.Point{}).SetBytes(key)
+	if err != nil {
+		return nil, err
+	}
+	return &Key{point}, nil
+}
+
 // creates a new pkix.Name
 func NewName(commonName, country, org string) pkix.Name {
 	res := NewCName(commonName)
@@ -99,9 +163,12 @@ func NewEndEntityCert(key ed25519.PrivateKey, req *x509.CertificateRequest, pare
 	return result, nil
 }
 
-func SaveCert(name string, cert *x509.Certificate) error {
+func SaveCert(path, name string, cert *x509.Certificate) error {
 	//certbytes, err := x509.ParseCertificate(cert)
-	certOut, err := os.Create(name + ".PEM")
+	if err := os.MkdirAll(path, 0644); err != nil {
+		return fmt.Errorf("failed to create dir %s %w", path, err)
+	}
+	certOut, err := os.Create(path + name)
 	if err != nil {
 		return fmt.Errorf("failed to open certficate file for writing: %v", err)
 	}
@@ -115,14 +182,17 @@ func SaveCert(name string, cert *x509.Certificate) error {
 	return nil
 }
 
-func SaveKey(name string, key *ed25519.PrivateKey) error {
+func SaveKey(path, name string, key ed25519.PrivateKey) error {
 	//func SaveKey(name string, key *ecdsa.PrivateKey) error {
-	keyOut, err := os.Create(name + ".key")
+	if err := os.MkdirAll(path, 0644); err != nil {
+		return fmt.Errorf("failed to create dir %s %w", path, err)
+	}
+	keyOut, err := os.Create(path + name)
 	if err != nil {
 		return fmt.Errorf("failed open key file for writing: %v", err)
 	}
 	defer keyOut.Close()
-	privBytes, err := x509.MarshalPKCS8PrivateKey(*key)
+	privBytes, err := x509.MarshalPKCS8PrivateKey(key)
 	if err != nil {
 		return fmt.Errorf("failedto marshal key %v ", err)
 	}