diff --git a/config-sample.yaml b/config-sample.yaml index 4916c9d05..189a8f263 100644 --- a/config-sample.yaml +++ b/config-sample.yaml @@ -87,6 +87,10 @@ rtc: # port: 443 # # tls, tcp, or udp # protocol: tls + # # Shared secret for TURN server authentication + # secret: "" + # ttl: 14400 # seconds + # # Insecure username/password authentication # username: "" # credential: "" # # allows LiveKit to monitor congestion when sending streams and automatically diff --git a/pkg/config/config.go b/pkg/config/config.go index 91b5919aa..fa5941c81 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -141,6 +141,12 @@ type TURNServer struct { Protocol string `yaml:"protocol,omitempty"` Username string `yaml:"username,omitempty"` Credential string `yaml:"credential,omitempty"` + // Secret is used for TURN static auth secrets mechanism. When provided, + // dynamic credentials are generated using HMAC-SHA1 instead of static Username/Credential + Secret string `yaml:"secret,omitempty"` + // TTL is the time-to-live in seconds for generated credentials when using Secret. + // Defaults to 14400 seconds (4 hours) if not specified + TTL int `yaml:"ttl,omitempty"` } type CongestionControlConfig struct { diff --git a/pkg/service/roommanager.go b/pkg/service/roommanager.go index 62c80b904..526e4cefa 100644 --- a/pkg/service/roommanager.go +++ b/pkg/service/roommanager.go @@ -16,6 +16,9 @@ package service import ( "context" + "crypto/hmac" + "crypto/sha1" + "encoding/base64" "fmt" "os" "sync" @@ -1018,12 +1021,35 @@ func (r *RoomManager) iceServersForParticipant(apiKey string, participant types. case "udp": transport = "udp" } + + var username, credential string + if s.Secret != "" { + // Generate dynamic credentials using TURN static auth secrets + ttl := s.TTL + if ttl == 0 { + ttl = 14400 // Default 4 hours + } + + expiry := time.Now().Add(time.Duration(ttl) * time.Second).Unix() + participantID := string(participant.ID()) + username = fmt.Sprintf("%d:%s", expiry, participantID) + + // HMAC-SHA1 signature + h := hmac.New(sha1.New, []byte(s.Secret)) + h.Write([]byte(username)) + credential = base64.StdEncoding.EncodeToString(h.Sum(nil)) + } else { + // Use static credentials + username = s.Username + credential = s.Credential + } + is := &livekit.ICEServer{ Urls: []string{ fmt.Sprintf("%s:%s:%d?transport=%s", scheme, s.Host, s.Port, transport), }, - Username: s.Username, - Credential: s.Credential, + Username: username, + Credential: credential, } iceServers = append(iceServers, is) }