2021-03-26 00:17:52 +08:00
package main
import (
2022-01-06 23:57:05 +08:00
"context"
2022-04-19 05:19:26 +08:00
"crypto/ed25519"
"crypto/rand"
"errors"
2022-03-23 05:22:34 +08:00
"flag"
2021-08-10 02:56:27 +08:00
"fmt"
2021-07-21 05:18:45 +08:00
"os"
"os/signal"
2021-11-17 10:19:13 +08:00
"runtime/debug"
2021-07-21 05:18:45 +08:00
"strconv"
"sync"
2022-01-15 03:30:26 +08:00
"syscall"
2022-04-19 05:19:26 +08:00
"time"
2021-08-19 06:12:08 +08:00
2021-10-22 03:28:58 +08:00
"github.com/gravitl/netmaker/auth"
2022-03-23 05:22:34 +08:00
"github.com/gravitl/netmaker/config"
2021-07-21 05:18:45 +08:00
controller "github.com/gravitl/netmaker/controllers"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/functions"
2021-12-07 04:31:08 +08:00
"github.com/gravitl/netmaker/logger"
2021-10-22 03:28:58 +08:00
"github.com/gravitl/netmaker/logic"
2021-08-10 02:56:27 +08:00
"github.com/gravitl/netmaker/models"
2022-01-13 05:23:34 +08:00
"github.com/gravitl/netmaker/mq"
2021-09-20 02:03:47 +08:00
"github.com/gravitl/netmaker/netclient/ncutils"
2021-07-21 05:18:45 +08:00
"github.com/gravitl/netmaker/servercfg"
2021-09-28 05:51:20 +08:00
"github.com/gravitl/netmaker/serverctl"
2022-04-19 05:19:26 +08:00
"github.com/gravitl/netmaker/tls"
2021-03-26 00:17:52 +08:00
)
2021-04-06 02:47:07 +08:00
2022-02-08 20:01:39 +08:00
var version = "dev"
2021-08-31 03:58:23 +08:00
// Start DB Connection and start API Request Handler
2021-03-26 00:17:52 +08:00
func main ( ) {
2022-03-23 05:22:34 +08:00
absoluteConfigPath := flag . String ( "c" , "" , "absolute path to configuration file" )
flag . Parse ( )
setupConfig ( * absoluteConfigPath )
2022-02-08 20:01:39 +08:00
servercfg . SetVersion ( version )
2021-08-10 02:56:27 +08:00
fmt . Println ( models . RetrieveLogo ( ) ) // print the logo
2022-04-22 03:53:44 +08:00
initialize ( ) // initial db and acls; gen cert if required
2021-11-17 10:19:13 +08:00
setGarbageCollection ( )
2021-08-19 06:12:08 +08:00
defer database . CloseDB ( )
2022-04-22 03:53:44 +08:00
startControllers ( ) // start the api endpoint and mq
2021-07-21 05:18:45 +08:00
}
2021-04-13 12:42:35 +08:00
2022-03-23 05:22:34 +08:00
func setupConfig ( absoluteConfigPath string ) {
if len ( absoluteConfigPath ) > 0 {
cfg , err := config . ReadConfig ( absoluteConfigPath )
if err != nil {
logger . Log ( 0 , fmt . Sprintf ( "failed parsing config at: %s" , absoluteConfigPath ) )
return
}
config . Config = cfg
}
}
2021-07-29 04:40:13 +08:00
func initialize ( ) { // Client Mode Prereq Check
2021-07-21 05:18:45 +08:00
var err error
2022-02-14 22:58:50 +08:00
if servercfg . GetMasterKey ( ) == "" {
logger . Log ( 0 , "warning: MASTER_KEY not set, this could make account recovery difficult" )
}
2022-02-01 22:59:23 +08:00
if servercfg . GetNodeID ( ) == "" {
2022-02-15 05:19:19 +08:00
logger . FatalLog ( "error: must set NODE_ID, currently blank" )
2022-02-01 22:59:23 +08:00
}
2021-07-29 04:40:13 +08:00
if err = database . InitializeDatabase ( ) ; err != nil {
2021-12-11 10:09:42 +08:00
logger . FatalLog ( "Error connecting to database" )
2021-07-29 04:40:13 +08:00
}
2021-12-07 04:31:08 +08:00
logger . Log ( 0 , "database successfully connected" )
2022-02-15 22:51:21 +08:00
logic . SetJWTSecret ( )
2021-10-22 03:28:58 +08:00
2022-01-26 00:00:56 +08:00
err = logic . TimerCheckpoint ( )
2022-01-21 06:50:42 +08:00
if err != nil {
2022-01-26 00:00:56 +08:00
logger . Log ( 1 , "Timer error occurred: " , err . Error ( ) )
2022-01-21 06:50:42 +08:00
}
2021-10-22 03:28:58 +08:00
var authProvider = auth . InitializeAuthProvider ( )
if authProvider != "" {
2021-12-29 01:07:50 +08:00
logger . Log ( 0 , "OAuth provider," , authProvider + "," , "initialized" )
2021-10-22 21:47:29 +08:00
} else {
2021-12-07 04:31:08 +08:00
logger . Log ( 0 , "no OAuth provider found or not configured, continuing without OAuth" )
2021-10-22 03:28:58 +08:00
}
2022-03-14 09:35:22 +08:00
err = serverctl . SetDefaultACLS ( )
if err != nil {
logger . FatalLog ( "error setting default acls: " , err . Error ( ) )
}
2021-09-28 05:51:20 +08:00
if servercfg . IsClientMode ( ) != "off" {
2021-09-20 02:03:47 +08:00
output , err := ncutils . RunCmd ( "id -u" , true )
2021-08-31 03:58:23 +08:00
if err != nil {
2021-12-07 04:31:08 +08:00
logger . FatalLog ( "Error running 'id -u' for prereq check. Please investigate or disable client mode." , output , err . Error ( ) )
2021-08-31 03:58:23 +08:00
}
uid , err := strconv . Atoi ( string ( output [ : len ( output ) - 1 ] ) )
if err != nil {
2021-12-07 04:31:08 +08:00
logger . FatalLog ( "Error retrieving uid from 'id -u' for prereq check. Please investigate or disable client mode." , err . Error ( ) )
2021-08-31 03:58:23 +08:00
}
if uid != 0 {
2021-12-07 04:31:08 +08:00
logger . FatalLog ( "To run in client mode requires root privileges. Either disable client mode or run with sudo." )
2021-08-31 03:58:23 +08:00
}
2021-09-29 02:08:16 +08:00
if err := serverctl . InitServerNetclient ( ) ; err != nil {
2021-12-07 04:31:08 +08:00
logger . FatalLog ( "Did not find netclient to use CLIENT_MODE" )
2021-09-29 02:08:16 +08:00
}
2021-07-21 05:18:45 +08:00
}
2022-01-26 00:58:51 +08:00
// initialize iptables to ensure gateways work correctly and mq is forwarded if containerized
if servercfg . ManageIPTables ( ) != "off" {
2022-03-28 22:36:23 +08:00
if err = serverctl . InitIPTables ( true ) ; err != nil {
2022-01-26 00:58:51 +08:00
logger . FatalLog ( "Unable to initialize iptables on host:" , err . Error ( ) )
}
}
2021-04-20 09:50:58 +08:00
2021-07-21 05:18:45 +08:00
if servercfg . IsDNSMode ( ) {
err := functions . SetDNSDir ( )
2021-05-06 04:42:17 +08:00
if err != nil {
2021-12-07 04:31:08 +08:00
logger . FatalLog ( err . Error ( ) )
2021-05-06 04:42:17 +08:00
}
2021-04-13 12:42:35 +08:00
}
2022-04-25 23:12:49 +08:00
2022-04-26 23:47:41 +08:00
genCerts ( )
2022-04-25 23:12:49 +08:00
if servercfg . IsMessageQueueBackend ( ) {
if err = mq . ServerStartNotify ( ) ; err != nil {
logger . Log ( 0 , "error occurred when notifying nodes of startup" , err . Error ( ) )
}
}
2022-06-14 03:19:25 +08:00
logic . InitalizeZombies ( )
2021-07-21 05:18:45 +08:00
}
2021-05-06 04:42:17 +08:00
2021-07-21 05:18:45 +08:00
func startControllers ( ) {
2021-04-13 12:42:35 +08:00
var waitnetwork sync . WaitGroup
2021-07-21 05:18:45 +08:00
if servercfg . IsDNSMode ( ) {
2021-10-27 00:27:29 +08:00
err := logic . SetDNS ( )
2021-07-21 05:18:45 +08:00
if err != nil {
2021-12-07 04:31:08 +08:00
logger . Log ( 0 , "error occurred initializing DNS: " , err . Error ( ) )
2021-07-21 05:18:45 +08:00
}
}
2021-05-06 04:42:17 +08:00
//Run Rest Server
2021-05-06 06:03:37 +08:00
if servercfg . IsRestBackend ( ) {
2021-07-21 05:18:45 +08:00
if ! servercfg . DisableRemoteIPCheck ( ) && servercfg . GetAPIHost ( ) == "127.0.0.1" {
err := servercfg . SetHost ( )
if err != nil {
2021-12-07 04:31:08 +08:00
logger . FatalLog ( "Unable to Set host. Exiting..." , err . Error ( ) )
2021-07-21 05:18:45 +08:00
}
}
2021-04-13 12:42:35 +08:00
waitnetwork . Add ( 1 )
2021-12-09 05:52:32 +08:00
go controller . HandleRESTRequests ( & waitnetwork )
2021-03-26 00:17:52 +08:00
}
2021-12-09 05:52:32 +08:00
2022-01-13 05:23:34 +08:00
//Run MessageQueue
if servercfg . IsMessageQueueBackend ( ) {
waitnetwork . Add ( 1 )
go runMessageQueue ( & waitnetwork )
}
if ! servercfg . IsAgentBackend ( ) && ! servercfg . IsRestBackend ( ) && ! servercfg . IsMessageQueueBackend ( ) {
logger . Log ( 0 , "No Server Mode selected, so nothing is being served! Set Agent mode (AGENT_BACKEND) or Rest mode (REST_BACKEND) or MessageQueue (MESSAGEQUEUE_BACKEND) to 'true'." )
2021-03-26 00:17:52 +08:00
}
2021-09-28 05:51:20 +08:00
2021-04-13 12:42:35 +08:00
waitnetwork . Wait ( )
2021-09-28 05:51:20 +08:00
}
2022-01-13 05:23:34 +08:00
// Should we be using a context vice a waitgroup????????????
func runMessageQueue ( wg * sync . WaitGroup ) {
defer wg . Done ( )
2022-02-11 00:07:21 +08:00
logger . Log ( 0 , "connecting to mq broker at" , servercfg . GetMessageQueueEndpoint ( ) )
2022-02-09 08:52:35 +08:00
var client = mq . SetupMQTT ( false ) // Set up the subscription listener
2022-01-27 02:42:52 +08:00
ctx , cancel := context . WithCancel ( context . Background ( ) )
go mq . Keepalive ( ctx )
2022-06-14 03:19:25 +08:00
go logic . ManageZombies ( ctx )
2022-01-15 03:30:26 +08:00
quit := make ( chan os . Signal , 1 )
signal . Notify ( quit , syscall . SIGTERM , os . Interrupt )
<- quit
2022-01-27 02:42:52 +08:00
cancel ( )
2022-01-15 03:30:26 +08:00
logger . Log ( 0 , "Message Queue shutting down" )
2022-01-25 04:33:36 +08:00
client . Disconnect ( 250 )
2022-01-13 05:23:34 +08:00
}
2021-11-17 10:19:13 +08:00
func setGarbageCollection ( ) {
_ , gcset := os . LookupEnv ( "GOGC" )
if ! gcset {
debug . SetGCPercent ( ncutils . DEFAULT_GC_PERCENT )
}
}
2022-04-19 05:19:26 +08:00
func genCerts ( ) error {
2022-04-19 22:14:02 +08:00
logger . Log ( 0 , "checking keys and certificates" )
var private * ed25519 . PrivateKey
var err error
2022-07-01 10:30:28 +08:00
private , err = serverctl . ReadKeyFromDB ( tls . ROOT_KEY_NAME )
2022-07-02 05:30:13 +08:00
if errors . Is ( err , os . ErrNotExist ) || database . IsEmptyRecord ( err ) {
2022-04-19 22:14:02 +08:00
logger . Log ( 0 , "generating new root key" )
_ , newKey , err := ed25519 . GenerateKey ( rand . Reader )
2022-04-19 05:19:26 +08:00
if err != nil {
return err
}
2022-07-01 10:30:28 +08:00
if err := serverctl . SaveKey ( functions . GetNetmakerPath ( ) + ncutils . GetSeparator ( ) , tls . ROOT_KEY_NAME , newKey ) ; err != nil {
2022-04-19 05:19:26 +08:00
return err
}
2022-04-19 22:14:02 +08:00
private = & newKey
2022-04-19 05:19:26 +08:00
} else if err != nil {
return err
}
2022-07-01 10:30:28 +08:00
ca , err := serverctl . ReadCertFromDB ( tls . ROOT_PEM_NAME )
2022-04-19 05:19:26 +08:00
//if cert doesn't exist or will expire within 10 days --- but can't do this as clients won't be able to connect
//if errors.Is(err, os.ErrNotExist) || cert.NotAfter.Before(time.Now().Add(time.Hour*24*10)) {
2022-07-02 05:30:13 +08:00
if errors . Is ( err , os . ErrNotExist ) || database . IsEmptyRecord ( err ) {
2022-04-19 22:14:02 +08:00
logger . Log ( 0 , "generating new root CA" )
2022-04-19 05:19:26 +08:00
caName := tls . NewName ( "CA Root" , "US" , "Gravitl" )
csr , err := tls . NewCSR ( * private , caName )
if err != nil {
return err
}
rootCA , err := tls . SelfSignedCA ( * private , csr , tls . CERTIFICATE_VALIDITY )
if err != nil {
return err
}
2022-07-01 10:30:28 +08:00
if err := serverctl . SaveCert ( functions . GetNetmakerPath ( ) + ncutils . GetSeparator ( ) , tls . ROOT_PEM_NAME , rootCA ) ; err != nil {
2022-04-19 05:19:26 +08:00
return err
}
2022-04-19 22:14:02 +08:00
ca = rootCA
2022-04-19 05:19:26 +08:00
} else if err != nil {
return err
}
2022-07-01 10:30:28 +08:00
cert , err := serverctl . ReadCertFromDB ( tls . SERVER_PEM_NAME )
2022-07-02 05:30:13 +08:00
if errors . Is ( err , os . ErrNotExist ) || database . IsEmptyRecord ( err ) || cert . NotAfter . Before ( time . Now ( ) . Add ( time . Hour * 24 * 10 ) ) {
2022-04-19 05:19:26 +08:00
//gen new key
2022-04-19 22:14:02 +08:00
logger . Log ( 0 , "generating new server key/certificate" )
2022-04-19 05:19:26 +08:00
_ , key , err := ed25519 . GenerateKey ( rand . Reader )
if err != nil {
return err
}
serverName := tls . NewCName ( servercfg . GetServer ( ) )
csr , err := tls . NewCSR ( key , serverName )
if err != nil {
return err
}
cert , err := tls . NewEndEntityCert ( * private , csr , ca , tls . CERTIFICATE_VALIDITY )
if err != nil {
return err
}
2022-07-01 10:30:28 +08:00
if err := serverctl . SaveKey ( functions . GetNetmakerPath ( ) + ncutils . GetSeparator ( ) , tls . SERVER_KEY_NAME , key ) ; err != nil {
2022-04-19 05:19:26 +08:00
return err
}
2022-07-01 10:30:28 +08:00
if err := serverctl . SaveCert ( functions . GetNetmakerPath ( ) + ncutils . GetSeparator ( ) , tls . SERVER_PEM_NAME , cert ) ; err != nil {
2022-04-19 05:19:26 +08:00
return err
}
} else if err != nil {
return err
}
return nil
}