feat(mediaserver): authenticate internal clients
This commit is contained in:
parent
3866d9dd07
commit
bcaf9f1cae
@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
@ -50,6 +51,7 @@ type Actor struct {
|
||||
rtmpPort int
|
||||
streamKey StreamKey
|
||||
fetchIngressStateInterval time.Duration
|
||||
pass string // password for the media server
|
||||
logger *slog.Logger
|
||||
httpClient *http.Client
|
||||
|
||||
@ -83,6 +85,7 @@ func StartActor(ctx context.Context, params StartActorParams) *Actor {
|
||||
rtmpPort: cmp.Or(params.RTMPPort, defaultRTMPPort),
|
||||
streamKey: cmp.Or(params.StreamKey, defaultStreamKey),
|
||||
fetchIngressStateInterval: cmp.Or(params.FetchIngressStateInterval, defaultFetchIngressStateInterval),
|
||||
pass: generatePassword(),
|
||||
actorC: make(chan action, chanSize),
|
||||
state: new(domain.Source),
|
||||
stateC: make(chan domain.Source, chanSize),
|
||||
@ -101,18 +104,26 @@ func StartActor(ctx context.Context, params StartActorParams) *Actor {
|
||||
LogDestinations: []string{"stdout"},
|
||||
AuthMethod: "internal",
|
||||
AuthInternalUsers: []User{
|
||||
// TODO: tighten permissions
|
||||
// TODO: TLS
|
||||
{
|
||||
User: "any",
|
||||
IPs: []string{}, // any IP
|
||||
Permissions: []UserPermission{
|
||||
{Action: "publish"},
|
||||
},
|
||||
},
|
||||
{
|
||||
User: "api",
|
||||
Pass: actor.pass,
|
||||
IPs: []string{}, // any IP
|
||||
Permissions: []UserPermission{
|
||||
{Action: "read"},
|
||||
},
|
||||
},
|
||||
{
|
||||
User: "any",
|
||||
IPs: []string{"127.0.0.1", "::1", "172.17.0.0/16"},
|
||||
User: "api",
|
||||
Pass: actor.pass,
|
||||
IPs: []string{}, // any IP
|
||||
Permissions: []UserPermission{{Action: "api"}},
|
||||
},
|
||||
},
|
||||
@ -144,7 +155,7 @@ func StartActor(ctx context.Context, params StartActorParams) *Actor {
|
||||
container.LabelComponent: componentName,
|
||||
},
|
||||
Healthcheck: &typescontainer.HealthConfig{
|
||||
Test: []string{"CMD", "curl", "-f", "http://localhost:9997/v3/paths/list"},
|
||||
Test: []string{"CMD", "curl", "-f", actor.pathsURL()},
|
||||
Interval: time.Second * 10,
|
||||
StartPeriod: time.Second * 2,
|
||||
StartInterval: time.Second * 2,
|
||||
@ -317,18 +328,18 @@ func (s *Actor) rtmpURL() string {
|
||||
// the app network.
|
||||
func (s *Actor) rtmpInternalURL() string {
|
||||
// Container port, not host port:
|
||||
return fmt.Sprintf("rtmp://mediaserver:1935/%s", s.streamKey)
|
||||
return fmt.Sprintf("rtmp://mediaserver:1935/%s?user=api&pass=%s", s.streamKey, s.pass)
|
||||
}
|
||||
|
||||
// rtmpConnsURL returns the URL for fetching RTMP connections, accessible from
|
||||
// the host.
|
||||
func (s *Actor) rtmpConnsURL() string {
|
||||
return fmt.Sprintf("http://localhost:%d/v3/rtmpconns/list", s.apiPort)
|
||||
return fmt.Sprintf("http://api:%s@localhost:%d/v3/rtmpconns/list", s.pass, s.apiPort)
|
||||
}
|
||||
|
||||
// pathsURL returns the URL for fetching paths, accessible from the host.
|
||||
func (s *Actor) pathsURL() string {
|
||||
return fmt.Sprintf("http://localhost:%d/v3/paths/list", s.apiPort)
|
||||
return fmt.Sprintf("http://api:%s@localhost:%d/v3/paths/list", s.pass, s.apiPort)
|
||||
}
|
||||
|
||||
// shortID returns the first 12 characters of the given container ID.
|
||||
@ -338,3 +349,12 @@ func shortID(id string) string {
|
||||
}
|
||||
return id[:12]
|
||||
}
|
||||
|
||||
// generatePassword securely generates a random password suitable for
|
||||
// authenticating media server endpoints.
|
||||
func generatePassword() string {
|
||||
const lenBytes = 32
|
||||
p := make([]byte, lenBytes)
|
||||
_, _ = rand.Read(p)
|
||||
return fmt.Sprintf("%x", []byte(p))
|
||||
}
|
||||
|
12
internal/mediaserver/actor_test.go
Normal file
12
internal/mediaserver/actor_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
package mediaserver
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGeneratePassword(t *testing.T) {
|
||||
assert.Len(t, generatePassword(), 64)
|
||||
assert.NotEqual(t, generatePassword(), generatePassword())
|
||||
}
|
@ -36,6 +36,7 @@ type UserPermission struct {
|
||||
// User represents a user configuration in MediaMTX.
|
||||
type User struct {
|
||||
User string `yaml:"user,omitempty"`
|
||||
Pass string `yaml:"pass,omitempty"`
|
||||
IPs []string `yaml:"ips,omitempty"`
|
||||
Permissions []UserPermission `yaml:"permissions,omitempty"`
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user