mirror of
https://github.com/livekit/livekit.git
synced 2026-03-30 19:55:41 +00:00
turn server tls (#38)
* tls * acm * use cert/key files * turn -> turns * turn cert config * updates * move panic * tidy * final updates
This commit is contained in:
@@ -41,8 +41,7 @@ func printPorts(c *cli.Context) error {
|
||||
|
||||
if conf.TURN.Enabled {
|
||||
udpPorts = append(udpPorts, fmt.Sprintf("%d-%d", conf.TURN.PortRangeStart, conf.TURN.PortRangeEnd))
|
||||
udpPorts = append(udpPorts, strconv.Itoa(conf.TURN.TCPPort))
|
||||
tcpPorts = append(tcpPorts, strconv.Itoa(conf.TURN.TCPPort))
|
||||
tcpPorts = append(tcpPorts, strconv.Itoa(conf.TURN.TLSPort))
|
||||
}
|
||||
|
||||
fmt.Println("TCP Ports")
|
||||
|
||||
@@ -75,6 +75,16 @@ func main() {
|
||||
Name: "dev",
|
||||
Usage: "sets log-level to debug, and console formatter",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "turn-cert",
|
||||
Usage: "tls cert file for TURN server",
|
||||
EnvVars: []string{"LIVEKIT_TURN_CERT"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "turn-key",
|
||||
Usage: "tls key file for TURN server",
|
||||
EnvVars: []string{"LIVEKIT_TURN_KEY"},
|
||||
},
|
||||
},
|
||||
Action: startServer,
|
||||
Commands: []*cli.Command{
|
||||
|
||||
@@ -65,3 +65,19 @@ keys:
|
||||
# update_interval: 500
|
||||
# # to prevent speaker updates from too jumpy, smooth out values over N samples
|
||||
# smooth_samples: 5
|
||||
|
||||
# turn server
|
||||
turn:
|
||||
# Uses TLS. Requires cert and key pem files by either:
|
||||
# - using turn.secretName if deploying with our helm chart, or
|
||||
# - setting LIVEKIT_TURN_CERT and LIVEKIT_TURN_KEY env vars with file locations, or
|
||||
# - using cert_file and key_file below
|
||||
# defaults to false
|
||||
enabled: false
|
||||
# needs to match tls cert domain
|
||||
domain: turn.myhost.com
|
||||
# defaults to 3478 - if not using a load balancer, this must be set to 443
|
||||
tls_port: 3478
|
||||
# optional
|
||||
# cert_file: /path/to/cert.pem
|
||||
# key_file: /path/to/key.pem
|
||||
|
||||
@@ -71,8 +71,10 @@ type RedisConfig struct {
|
||||
|
||||
type TURNConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
TCPPort int `yaml:"tcp_port"`
|
||||
UDPPort int `yaml:"udp_port"`
|
||||
Domain string `yaml:"domain"`
|
||||
CertFile string `yaml:"cert_file"`
|
||||
KeyFile string `yaml:"key_file"`
|
||||
TLSPort int `yaml:"tls_port"`
|
||||
PortRangeStart uint16 `yaml:"port_range_start"`
|
||||
PortRangeEnd uint16 `yaml:"port_range_end"`
|
||||
}
|
||||
@@ -108,8 +110,7 @@ func NewConfig(confString string) (*Config, error) {
|
||||
Redis: RedisConfig{},
|
||||
TURN: TURNConfig{
|
||||
Enabled: false,
|
||||
TCPPort: 3478,
|
||||
UDPPort: 3478,
|
||||
TLSPort: 3478,
|
||||
PortRangeStart: 12000,
|
||||
PortRangeEnd: 14000,
|
||||
},
|
||||
@@ -143,6 +144,12 @@ func (conf *Config) UpdateFromCLI(c *cli.Context) error {
|
||||
if c.IsSet("redis-password") {
|
||||
conf.Redis.Password = c.String("redis-password")
|
||||
}
|
||||
if c.IsSet("turn-cert") {
|
||||
conf.TURN.CertFile = c.String("turn-cert")
|
||||
}
|
||||
if c.IsSet("turn-key") {
|
||||
conf.TURN.KeyFile = c.String("turn-key")
|
||||
}
|
||||
// expand env vars in filenames
|
||||
file, err := homedir.Expand(os.ExpandEnv(conf.KeyFile))
|
||||
if err != nil {
|
||||
|
||||
@@ -480,21 +480,11 @@ func (r *RoomManager) iceServersForRoom(ri *livekit.Room) []*livekit.ICEServer {
|
||||
})
|
||||
}
|
||||
if r.config.TURN.Enabled {
|
||||
if r.config.TURN.TCPPort > 0 {
|
||||
iceServers = append(iceServers, &livekit.ICEServer{
|
||||
Urls: []string{fmt.Sprintf("turn:%s:%d?transport=tcp", r.currentNode.Ip, r.config.TURN.TCPPort)},
|
||||
Username: ri.Name,
|
||||
Credential: ri.TurnPassword,
|
||||
})
|
||||
}
|
||||
|
||||
if r.config.TURN.UDPPort > 0 {
|
||||
iceServers = append(iceServers, &livekit.ICEServer{
|
||||
Urls: []string{fmt.Sprintf("turn:%s:%d?transport=udp", r.currentNode.Ip, r.config.TURN.UDPPort)},
|
||||
Username: ri.Name,
|
||||
Credential: ri.TurnPassword,
|
||||
})
|
||||
}
|
||||
iceServers = append(iceServers, &livekit.ICEServer{
|
||||
Urls: []string{fmt.Sprintf("turns:%s:443?transport=tcp", r.config.TURN.Domain)},
|
||||
Username: ri.Name,
|
||||
Credential: ri.TurnPassword,
|
||||
})
|
||||
}
|
||||
return iceServers
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
@@ -23,19 +24,32 @@ func NewTurnServer(conf *config.Config, roomStore RoomStore, node routing.LocalN
|
||||
if !turnConf.Enabled {
|
||||
return nil, nil
|
||||
}
|
||||
if turnConf.Domain == "" {
|
||||
return nil, errors.New("TURN domain required")
|
||||
}
|
||||
if turnConf.TLSPort == 0 {
|
||||
return nil, errors.New("invalid TURN tcp port")
|
||||
}
|
||||
|
||||
cert, err := tls.LoadX509KeyPair(turnConf.CertFile, turnConf.KeyFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "TURN tls cert required")
|
||||
}
|
||||
|
||||
tlsListener, err := tls.Listen("tcp4", "0.0.0.0:"+strconv.Itoa(turnConf.TLSPort), &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not listen on TURN TCP port")
|
||||
}
|
||||
|
||||
serverConfig := turn.ServerConfig{
|
||||
Realm: livekitRealm,
|
||||
AuthHandler: newTurnAuthHandler(roomStore),
|
||||
}
|
||||
|
||||
if turnConf.TCPPort > 0 {
|
||||
tcpListener, err := net.Listen("tcp4", "0.0.0.0:"+strconv.Itoa(turnConf.TCPPort))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not listen on TURN TCP port")
|
||||
}
|
||||
serverConfig.ListenerConfigs = []turn.ListenerConfig{
|
||||
ListenerConfigs: []turn.ListenerConfig{
|
||||
{
|
||||
Listener: tcpListener,
|
||||
Listener: tlsListener,
|
||||
RelayAddressGenerator: &turn.RelayAddressGeneratorPortRange{
|
||||
RelayAddress: net.ParseIP(node.Ip),
|
||||
Address: "0.0.0.0",
|
||||
@@ -44,31 +58,11 @@ func NewTurnServer(conf *config.Config, roomStore RoomStore, node routing.LocalN
|
||||
MaxRetries: allocateRetries,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if turnConf.UDPPort > 0 {
|
||||
udpListener, err := net.ListenPacket("udp4", "0.0.0.0:"+strconv.Itoa(turnConf.UDPPort))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not listen on TURN UDP port")
|
||||
}
|
||||
serverConfig.PacketConnConfigs = []turn.PacketConnConfig{
|
||||
{
|
||||
PacketConn: udpListener,
|
||||
RelayAddressGenerator: &turn.RelayAddressGeneratorPortRange{
|
||||
RelayAddress: net.ParseIP(node.Ip), // Claim that we are listening on IP passed by user (This should be your Public IP)
|
||||
Address: "0.0.0.0", // But actually be listening on every interface
|
||||
MinPort: turnConf.PortRangeStart,
|
||||
MaxPort: turnConf.PortRangeEnd,
|
||||
MaxRetries: allocateRetries,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
logger.Infow("Starting TURN server",
|
||||
"TCP port", turnConf.TCPPort,
|
||||
"UDP port", turnConf.UDPPort,
|
||||
"TCP port", turnConf.TLSPort,
|
||||
"portRange", fmt.Sprintf("%d-%d", turnConf.PortRangeStart, turnConf.PortRangeEnd))
|
||||
return turn.NewServer(serverConfig)
|
||||
}
|
||||
|
||||
@@ -9,14 +9,15 @@ import (
|
||||
"github.com/pion/turn/v2"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/livekit/protocol/utils"
|
||||
|
||||
"github.com/livekit/livekit-server/pkg/config"
|
||||
"github.com/livekit/livekit-server/pkg/routing"
|
||||
"github.com/livekit/livekit-server/pkg/service"
|
||||
livekit "github.com/livekit/livekit-server/proto"
|
||||
"github.com/livekit/protocol/utils"
|
||||
)
|
||||
|
||||
func TestTurnServer(t *testing.T) {
|
||||
func testTurnServer(t *testing.T) {
|
||||
conf, err := config.NewConfig("")
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -47,15 +48,15 @@ func TestTurnServer(t *testing.T) {
|
||||
require.NoError(t, roomStore.CreateRoom(rm))
|
||||
|
||||
turnConf := &turn.ClientConfig{
|
||||
STUNServerAddr: fmt.Sprintf("localhost:%d", conf.TURN.UDPPort),
|
||||
TURNServerAddr: fmt.Sprintf("%s:%d", currentNode.Ip, conf.TURN.UDPPort),
|
||||
STUNServerAddr: fmt.Sprintf("localhost:%d", conf.TURN.TLSPort),
|
||||
TURNServerAddr: fmt.Sprintf("%s:%d", currentNode.Ip, conf.TURN.TLSPort),
|
||||
Username: rm.Name,
|
||||
Password: rm.TurnPassword,
|
||||
Realm: "livekit",
|
||||
}
|
||||
|
||||
t.Run("TURN works over TCP", func(t *testing.T) {
|
||||
conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%d", conf.TURN.TCPPort))
|
||||
conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%d", conf.TURN.TLSPort))
|
||||
require.NoError(t, err)
|
||||
|
||||
tc := *turnConf
|
||||
|
||||
Reference in New Issue
Block a user