2024-05-17 20:24:06 +02:00
package main
import (
2024-07-01 11:50:18 +02:00
"crypto/tls"
"fmt"
2024-05-17 20:24:06 +02:00
"os"
2024-05-27 09:42:27 +02:00
"os/signal"
"syscall"
2024-07-08 17:01:11 +02:00
"time"
2024-05-23 13:24:02 +02:00
2024-05-17 20:24:06 +02:00
log "github.com/sirupsen/logrus"
2024-06-19 17:40:16 +02:00
"github.com/spf13/cobra"
2024-05-17 20:24:06 +02:00
2024-07-01 11:50:18 +02:00
"github.com/netbirdio/netbird/encryption"
2024-07-08 17:01:11 +02:00
auth "github.com/netbirdio/netbird/relay/auth/hmac"
2024-05-17 20:24:06 +02:00
"github.com/netbirdio/netbird/relay/server"
2024-05-27 09:42:27 +02:00
"github.com/netbirdio/netbird/util"
2024-05-17 20:24:06 +02:00
)
2024-06-19 17:40:16 +02:00
var (
2024-07-02 11:57:17 +02:00
listenAddress string
// in HA every peer connect to a common domain, the instance domain has been distributed during the p2p connection
2024-07-03 15:03:57 +02:00
// it is a domain:port or ip:port
2024-07-02 11:57:17 +02:00
exposedAddress string
2024-07-01 11:50:18 +02:00
letsencryptDataDir string
2024-07-02 11:57:17 +02:00
letsencryptDomains [ ] string
2024-07-03 15:03:57 +02:00
tlsCertFile string
tlsKeyFile string
2024-07-05 16:12:30 +02:00
authSecret string
2024-06-19 17:40:16 +02:00
rootCmd = & cobra . Command {
Use : "relay" ,
Short : "Relay service" ,
Long : "Relay service for Netbird agents" ,
Run : execute ,
}
)
2024-05-17 20:24:06 +02:00
func init ( ) {
2024-06-19 17:40:16 +02:00
_ = util . InitLog ( "trace" , "console" )
2024-07-03 15:03:57 +02:00
rootCmd . PersistentFlags ( ) . StringVarP ( & listenAddress , "listen-address" , "l" , ":443" , "listen address" )
2024-07-02 11:57:17 +02:00
rootCmd . PersistentFlags ( ) . StringVarP ( & exposedAddress , "exposed-address" , "e" , "" , "instance domain address (or ip) and port, it will be distributes between peers" )
2024-07-01 11:50:18 +02:00
rootCmd . PersistentFlags ( ) . StringVarP ( & letsencryptDataDir , "letsencrypt-data-dir" , "d" , "" , "a directory to store Let's Encrypt data. Required if Let's Encrypt is enabled." )
2024-07-02 11:57:17 +02:00
rootCmd . PersistentFlags ( ) . StringArrayVarP ( & letsencryptDomains , "letsencrypt-domains" , "a" , nil , "list of domains to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS" )
2024-07-03 15:03:57 +02:00
rootCmd . PersistentFlags ( ) . StringVarP ( & tlsCertFile , "tls-cert-file" , "c" , "" , "" )
rootCmd . PersistentFlags ( ) . StringVarP ( & tlsKeyFile , "tls-key-file" , "k" , "" , "" )
2024-07-05 16:12:30 +02:00
rootCmd . PersistentFlags ( ) . StringVarP ( & authSecret , "auth-secret" , "s" , "" , "log level" )
2024-05-17 20:24:06 +02:00
}
2024-05-27 09:42:27 +02:00
func waitForExitSignal ( ) {
osSigs := make ( chan os . Signal , 1 )
signal . Notify ( osSigs , syscall . SIGINT , syscall . SIGTERM )
2024-06-25 15:13:08 +02:00
<- osSigs
2024-05-27 09:42:27 +02:00
}
2024-05-17 20:24:06 +02:00
2024-06-19 17:40:16 +02:00
func execute ( cmd * cobra . Command , args [ ] string ) {
2024-07-03 15:03:57 +02:00
if exposedAddress == "" {
log . Errorf ( "exposed address is required" )
os . Exit ( 1 )
}
2024-07-05 16:12:30 +02:00
if authSecret == "" {
log . Errorf ( "auth secret is required" )
os . Exit ( 1 )
}
2024-07-02 11:57:17 +02:00
srvListenerCfg := server . ListenerConfig {
2024-07-01 11:50:18 +02:00
Address : listenAddress ,
}
if hasLetsEncrypt ( ) {
2024-07-03 15:03:57 +02:00
tlsCfg , err := setupTLSCertManager ( )
2024-07-01 11:50:18 +02:00
if err != nil {
log . Errorf ( "%s" , err )
os . Exit ( 1 )
}
2024-07-03 15:03:57 +02:00
srvListenerCfg . TLSConfig = tlsCfg
} else if hasCertConfig ( ) {
tlsCfg , err := encryption . LoadTLSConfig ( tlsCertFile , tlsKeyFile )
if err != nil {
log . Errorf ( "%s" , err )
os . Exit ( 1 )
}
srvListenerCfg . TLSConfig = tlsCfg
2024-07-01 11:50:18 +02:00
}
2024-07-02 11:57:17 +02:00
tlsSupport := srvListenerCfg . TLSConfig != nil
2024-07-08 17:01:11 +02:00
authenticator := auth . NewTimedHMACValidator ( authSecret , 24 * time . Hour )
srv := server . NewServer ( exposedAddress , tlsSupport , authenticator )
2024-07-03 15:03:57 +02:00
log . Infof ( "server will be available on: %s" , srv . InstanceURL ( ) )
2024-07-02 11:57:17 +02:00
err := srv . Listen ( srvListenerCfg )
2024-05-17 20:24:06 +02:00
if err != nil {
log . Errorf ( "failed to bind server: %s" , err )
os . Exit ( 1 )
}
2024-05-26 22:14:33 +02:00
2024-05-27 09:42:27 +02:00
waitForExitSignal ( )
err = srv . Close ( )
if err != nil {
log . Errorf ( "failed to close server: %s" , err )
os . Exit ( 1 )
}
2024-05-17 20:24:06 +02:00
}
2024-06-19 17:40:16 +02:00
2024-07-03 15:03:57 +02:00
func hasCertConfig ( ) bool {
return tlsCertFile != "" && tlsKeyFile != ""
}
2024-07-01 11:50:18 +02:00
func hasLetsEncrypt ( ) bool {
2024-07-02 11:57:17 +02:00
return letsencryptDataDir != "" && letsencryptDomains != nil && len ( letsencryptDomains ) > 0
2024-07-01 11:50:18 +02:00
}
2024-07-03 15:03:57 +02:00
func setupTLSCertManager ( ) ( * tls . Config , error ) {
2024-07-02 11:57:17 +02:00
certManager , err := encryption . CreateCertManager ( letsencryptDataDir , letsencryptDomains ... )
2024-07-01 11:50:18 +02:00
if err != nil {
return nil , fmt . Errorf ( "failed creating LetsEncrypt cert manager: %v" , err )
}
return certManager . TLSConfig ( ) , nil
}
2024-06-19 17:40:16 +02:00
func main ( ) {
err := rootCmd . Execute ( )
if err != nil {
os . Exit ( 1 )
}
}