mirror of
https://github.com/netbirdio/netbird.git
synced 2025-08-14 17:28:56 +02:00
TLS configuration
- handle the same AlPN list - use dev build tag for debugging purposes
This commit is contained in:
@ -2,7 +2,7 @@ package quic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
@ -11,27 +11,16 @@ import (
|
||||
"github.com/quic-go/quic-go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
quictls "github.com/netbirdio/netbird/relay/tls"
|
||||
nbnet "github.com/netbirdio/netbird/util/net"
|
||||
)
|
||||
|
||||
const (
|
||||
dialTimeout = 30 * time.Second
|
||||
)
|
||||
|
||||
func Dial(address string) (net.Conn, error) {
|
||||
func Dial(ctx context.Context, address string) (net.Conn, error) {
|
||||
quicURL, err := prepareURL(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), dialTimeout)
|
||||
defer cancel()
|
||||
|
||||
tlsConf := &tls.Config{
|
||||
InsecureSkipVerify: true, // Set to true only for testing
|
||||
NextProtos: []string{"netbird-relay"}, // Ensure this matches the server's ALPN
|
||||
}
|
||||
|
||||
quicConfig := &quic.Config{
|
||||
KeepAlivePeriod: 15 * time.Second,
|
||||
MaxIdleTimeout: 60 * time.Second,
|
||||
@ -50,8 +39,12 @@ func Dial(address string) (net.Conn, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session, err := quic.Dial(ctx, udpConn, udpAddr, tlsConf, quicConfig)
|
||||
session, err := quic.Dial(ctx, udpConn, udpAddr, quictls.ClientQUICTLSConfig(), quicConfig)
|
||||
if err != nil {
|
||||
if errors.Is(ctx.Err(), context.Canceled) {
|
||||
log.Infof("QUIC connection aborted to: %s", quicURL)
|
||||
return nil, err
|
||||
}
|
||||
log.Errorf("failed to dial to Relay server via QUIC '%s': %s", quicURL, err)
|
||||
return nil, err
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package ws
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
@ -16,7 +16,7 @@ import (
|
||||
nbnet "github.com/netbirdio/netbird/util/net"
|
||||
)
|
||||
|
||||
func Dial(address string) (net.Conn, error) {
|
||||
func Dial(ctx context.Context, address string) (net.Conn, error) {
|
||||
wsURL, err := prepareURL(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -32,8 +32,12 @@ func Dial(address string) (net.Conn, error) {
|
||||
}
|
||||
parsedURL.Path = ws.URLPath
|
||||
|
||||
wsConn, resp, err := websocket.Dial(context.Background(), parsedURL.String(), opts)
|
||||
wsConn, resp, err := websocket.Dial(ctx, parsedURL.String(), opts)
|
||||
if err != nil {
|
||||
if errors.Is(ctx.Err(), context.Canceled) {
|
||||
log.Infof("WebSocket connection aborted to: %s", wsURL)
|
||||
return nil, err
|
||||
}
|
||||
log.Errorf("failed to dial to Relay server '%s': %s", wsURL, err)
|
||||
return nil, err
|
||||
}
|
||||
@ -60,10 +64,6 @@ func httpClientNbDialer() *http.Client {
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return customDialer.DialContext(ctx, network, addr)
|
||||
},
|
||||
// Set up a TLS configuration that skips certificate verification
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true, // This accepts invalid TLS certificates
|
||||
},
|
||||
}
|
||||
|
||||
return &http.Client{
|
||||
|
@ -2,19 +2,10 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"math/big"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
|
||||
nberrors "github.com/netbirdio/netbird/client/errors"
|
||||
@ -22,6 +13,7 @@ import (
|
||||
"github.com/netbirdio/netbird/relay/server/listener"
|
||||
"github.com/netbirdio/netbird/relay/server/listener/quic"
|
||||
"github.com/netbirdio/netbird/relay/server/listener/ws"
|
||||
quictls "github.com/netbirdio/netbird/relay/tls"
|
||||
)
|
||||
|
||||
// ListenerConfig is the configuration for the listener.
|
||||
@ -64,19 +56,16 @@ func (r *Server) Listen(cfg ListenerConfig) error {
|
||||
}
|
||||
r.listeners = append(r.listeners, wSListener)
|
||||
|
||||
quicListener := &quic.Listener{
|
||||
Address: cfg.Address,
|
||||
tlsConfigQUIC, err := quictls.ServerQUICTLSConfig(cfg.TLSConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cfg.TLSConfig != nil {
|
||||
quicListener.TLSConfig = cfg.TLSConfig
|
||||
} else {
|
||||
tlsConfig, err := generateTestTLSConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
quicListener.TLSConfig = tlsConfig
|
||||
quicListener := &quic.Listener{
|
||||
Address: cfg.Address,
|
||||
TLSConfig: tlsConfigQUIC,
|
||||
}
|
||||
|
||||
r.listeners = append(r.listeners, quicListener)
|
||||
|
||||
errChan := make(chan error, len(r.listeners))
|
||||
@ -117,54 +106,3 @@ func (r *Server) Shutdown(ctx context.Context) error {
|
||||
func (r *Server) InstanceURL() string {
|
||||
return r.relay.instanceURL
|
||||
}
|
||||
|
||||
// GenerateTestTLSConfig creates a self-signed certificate for testing
|
||||
func generateTestTLSConfig() (*tls.Config, error) {
|
||||
log.Infof("generating test TLS config")
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
template := x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"Test Organization"},
|
||||
},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().Add(time.Hour * 24 * 180), // Valid for 180 days
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{
|
||||
x509.ExtKeyUsageServerAuth,
|
||||
},
|
||||
BasicConstraintsValid: true,
|
||||
DNSNames: []string{"localhost"},
|
||||
IPAddresses: []net.IP{net.ParseIP("192.168.0.10")},
|
||||
}
|
||||
|
||||
// Create certificate
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: certDER,
|
||||
})
|
||||
|
||||
privateKeyPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
|
||||
})
|
||||
|
||||
tlsCert, err := tls.X509KeyPair(certPEM, privateKeyPEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{tlsCert},
|
||||
NextProtos: []string{"netbird-relay"},
|
||||
}, nil
|
||||
}
|
||||
|
3
relay/tls/alpn.go
Normal file
3
relay/tls/alpn.go
Normal file
@ -0,0 +1,3 @@
|
||||
package tls
|
||||
|
||||
const nbalpn = "nb-quic"
|
12
relay/tls/client_dev.go
Normal file
12
relay/tls/client_dev.go
Normal file
@ -0,0 +1,12 @@
|
||||
//go:build dev
|
||||
|
||||
package tls
|
||||
|
||||
import "crypto/tls"
|
||||
|
||||
func ClientQUICTLSConfig() *tls.Config {
|
||||
return &tls.Config{
|
||||
InsecureSkipVerify: true, // Debug mode allows insecure connections
|
||||
NextProtos: []string{nbalpn}, // Ensure this matches the server's ALPN
|
||||
}
|
||||
}
|
11
relay/tls/client_prod.go
Normal file
11
relay/tls/client_prod.go
Normal file
@ -0,0 +1,11 @@
|
||||
//go:build !dev
|
||||
|
||||
package tls
|
||||
|
||||
import "crypto/tls"
|
||||
|
||||
func ClientQUICTLSConfig() *tls.Config {
|
||||
return &tls.Config{
|
||||
NextProtos: []string{nbalpn},
|
||||
}
|
||||
}
|
37
relay/tls/doc.go
Normal file
37
relay/tls/doc.go
Normal file
@ -0,0 +1,37 @@
|
||||
// Package tls provides utilities for configuring and managing
|
||||
// Transport Layer Security (TLS) in server environments, with
|
||||
// a focus on QUIC protocol support and testing configurations.
|
||||
//
|
||||
// The package includes functions for cloning and customizing
|
||||
// TLS configurations as well as generating self-signed
|
||||
// certificates for development and testing purposes.
|
||||
//
|
||||
// Key Features:
|
||||
//
|
||||
// - `ServerQUICTLSConfig`: Creates a server-side TLS configuration
|
||||
// tailored for QUIC protocol with specified or default settings.
|
||||
// QUIC requires a specific TLS configuration with proper ALPN
|
||||
// (Application-Layer Protocol Negotiation) support, making the
|
||||
// TLS settings crucial for establishing secure connections.
|
||||
//
|
||||
// - `ClientQUICTLSConfig`: Provides a client-side TLS configuration
|
||||
// suitable for QUIC protocol. The configuration differs between
|
||||
// development (insecure testing) and production (strict verification).
|
||||
//
|
||||
// - `generateTestTLSConfig`: Generates a self-signed TLS configuration
|
||||
// for use in local development and testing scenarios.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// This package provides separate implementations for development
|
||||
// and production environments. The development implementation
|
||||
// (guarded by `//go:build dev`) supports testing configurations
|
||||
// with self-signed certificates and insecure client connections.
|
||||
// The production implementation (guarded by `//go:build !dev`)
|
||||
// ensures that valid and secure TLS configurations are supplied
|
||||
// and used.
|
||||
//
|
||||
// The QUIC protocol is highly reliant on properly configured TLS
|
||||
// settings, and this package ensures that configurations meet the
|
||||
// requirements for secure and efficient QUIC communication.
|
||||
package tls
|
71
relay/tls/server_dev.go
Normal file
71
relay/tls/server_dev.go
Normal file
@ -0,0 +1,71 @@
|
||||
//go:build dev
|
||||
|
||||
package tls
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func ServerQUICTLSConfig(originTLSCfg *tls.Config) (*tls.Config, error) {
|
||||
if originTLSCfg == nil {
|
||||
log.Warnf("QUIC server will use self signed certificate for testing!")
|
||||
return generateTestTLSConfig()
|
||||
}
|
||||
|
||||
cfg := originTLSCfg.Clone()
|
||||
cfg.NextProtos = []string{"nb"}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// GenerateTestTLSConfig creates a self-signed certificate for testing
|
||||
func generateTestTLSConfig() (*tls.Config, error) {
|
||||
log.Infof("generating test TLS config")
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
template := x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"Test Organization"},
|
||||
},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().Add(time.Hour * 24 * 180), // Valid for 180 days
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{
|
||||
x509.ExtKeyUsageServerAuth,
|
||||
},
|
||||
BasicConstraintsValid: true,
|
||||
DNSNames: []string{"localhost"},
|
||||
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
|
||||
}
|
||||
|
||||
// Create certificate
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: certDER,
|
||||
})
|
||||
|
||||
privateKeyPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
|
||||
})
|
||||
|
||||
tlsCert, err := tls.X509KeyPair(certPEM, privateKeyPEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{tlsCert},
|
||||
NextProtos: []string{nbalpn},
|
||||
}, nil
|
||||
}
|
17
relay/tls/server_prod.go
Normal file
17
relay/tls/server_prod.go
Normal file
@ -0,0 +1,17 @@
|
||||
//go:build !dev
|
||||
|
||||
package tls
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ServerQUICTLSConfig(originTLSCfg *tls.Config) (*tls.Config, error) {
|
||||
if originTLSCfg == nil {
|
||||
return nil, fmt.Errorf("valid TLS config is required for QUIC listener")
|
||||
}
|
||||
cfg := originTLSCfg.Clone()
|
||||
cfg.NextProtos = []string{nbalpn}
|
||||
return cfg, nil
|
||||
}
|
Reference in New Issue
Block a user