Unverified Commit 7cd06772 authored by Martin Weinelt's avatar Martin Weinelt Committed by GitHub
Browse files

nixos/livekit: init, nixos/lk-jwt-service: init (#399627)

parents 8ba495f5 ba9ab12d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -752,6 +752,7 @@
  ./services/matrix/dendrite.nix
  ./services/matrix/hebbot.nix
  ./services/matrix/hookshot.nix
  ./services/matrix/lk-jwt-service.nix
  ./services/matrix/matrix-alertmanager.nix
  ./services/matrix/maubot.nix
  ./services/matrix/mautrix-meta.nix
@@ -1181,6 +1182,7 @@
  ./services/networking/lambdabot.nix
  ./services/networking/legit.nix
  ./services/networking/libreswan.nix
  ./services/networking/livekit.nix
  ./services/networking/lldpd.nix
  ./services/networking/logmein-hamachi.nix
  ./services/networking/lokinet.nix
+93 −0
Original line number Diff line number Diff line
{
  config,
  lib,
  pkgs,
  ...
}:
let
  cfg = config.services.lk-jwt-service;
in
{
  meta.maintainers = [ lib.maintainers.quadradical ];
  options.services.lk-jwt-service = {
    enable = lib.mkEnableOption "Enable lk-jwt-service";
    package = lib.mkPackageOption pkgs "lk-jwt-service" { };

    livekitUrl = lib.mkOption {
      type = lib.types.strMatching "^wss?://.*";
      example = "wss://example.com/livekit/sfu";
      description = ''
        The public websocket URL for livekit.
        The proto needs to be either  `wss://` (recommended) or `ws://` (insecure).
      '';
    };

    keyFile = lib.mkOption {
      type = lib.types.path;
      description = ''
        Path to a file containing the credential mapping (`<keyname>: <secret>`) to access LiveKit.

        Example:
        ```
          lk-jwt-service: f6lQGaHtM5HfgZjIcec3cOCRfiDqIine4CpZZnqdT5cE
        ```

        For more information, see <https://github.com/element-hq/lk-jwt-service#configuration>.
      '';
    };

    port = lib.mkOption {
      type = lib.types.port;
      default = 8080;
      description = "Port that lk-jwt-service should listen on.";
    };
  };

  config = lib.mkIf cfg.enable {
    systemd.services.lk-jwt-service = {
      description = "Minimal service to issue LiveKit JWTs for MatrixRTC";
      documentation = [ "https://github.com/element-hq/lk-jwt-service" ];
      wantedBy = [ "multi-user.target" ];
      wants = [ "network-online.target" ];
      after = [ "network-online.target" ];
      environment = {
        LIVEKIT_URL = cfg.livekitUrl;
        LIVEKIT_JWT_PORT = toString cfg.port;
        LIVEKIT_KEY_FILE = "/run/credentials/lk-jwt-service.service/livekit-secrets";
      };

      serviceConfig = {
        LoadCredential = [ "livekit-secrets:${cfg.keyFile}" ];
        ExecStart = lib.getExe cfg.package;
        DynamicUser = true;
        LockPersonality = true;
        MemoryDenyWriteExecute = true;
        ProtectClock = true;
        ProtectControlGroups = true;
        ProtectHostname = true;
        ProtectKernelLogs = true;
        ProtectKernelModules = true;
        ProtectKernelTunables = true;
        PrivateDevices = true;
        PrivateMounts = true;
        PrivateUsers = true;
        RestrictAddressFamilies = [
          "AF_INET"
          "AF_INET6"
        ];
        RestrictNamespaces = true;
        RestrictRealtime = true;
        ProtectHome = true;
        SystemCallArchitectures = "native";
        SystemCallFilter = [
          "@system-service"
          "~@privileged"
          "~@resources"
        ];
        Restart = "on-failure";
        RestartSec = 5;
        UMask = "077";
      };
    };
  };
}
+141 −0
Original line number Diff line number Diff line
{
  config,
  lib,
  pkgs,
  utils,
  ...
}:
let
  cfg = config.services.livekit;
  format = pkgs.formats.json { };
in
{
  meta.maintainers = with lib.maintainers; [ quadradical ];
  options.services.livekit = {
    enable = lib.mkEnableOption "Enable the livekit server";
    package = lib.mkPackageOption pkgs "livekit" { };

    keyFile = lib.mkOption {
      type = lib.types.path;
      description = ''
        LiveKit key file holding one or multiple application secrets. Use `livekit-server generate-keys` to generate a random key name and secret.

        The file should have the format `<keyname>: <secret>`. Example:
        ```
          lk-jwt-service: f6lQGaHtM5HfgZjIcec3cOCRfiDqIine4CpZZnqdT5cE
        ```

        Individual key/secret pairs need to be passed to clients to connect to this instance.
      '';
    };

    openFirewall = lib.mkOption {
      type = lib.types.bool;
      default = false;
      description = "Opens port range for LiveKit on the firewall.";
    };

    settings = lib.mkOption {
      type = lib.types.submodule {
        freeformType = format.type;
        options = {
          port = lib.mkOption {
            type = lib.types.port;
            default = 7880;
            description = "Main TCP port for RoomService and RTC endpoint.";
          };

          rtc = {
            port_range_start = lib.mkOption {
              type = lib.types.int;
              default = 50000;
              description = "Start of UDP port range for WebRTC";
            };

            port_range_end = lib.mkOption {
              type = lib.types.int;
              default = 51000;
              description = "End of UDP port range for WebRTC";
            };

            use_external_ip = lib.mkOption {
              type = lib.types.bool;
              default = false;
              description = ''
                When set to true, attempts to discover the host's public IP via STUN.
                This is useful for cloud environments such as AWS & Google where hosts have an internal IP that maps to an external one.
              '';
            };
          };
        };
      };
      default = { };
      description = ''
        LiveKit configuration file expressed in nix.

        For an example configuration, see <https://docs.livekit.io/home/self-hosting/deployment/#configuration>.
        For all possible values, see <https://github.com/livekit/livekit/blob/master/config-sample.yaml>.
      '';
    };
  };

  config = lib.mkIf cfg.enable {
    networking.firewall = lib.mkIf cfg.openFirewall {
      allowedTCPPorts = [
        cfg.settings.port
      ];
      allowedUDPPortRanges = [
        {
          from = cfg.settings.rtc.port_range_start;
          to = cfg.settings.rtc.port_range_end;
        }
      ];
    };

    systemd.services.livekit = {
      description = "LiveKit SFU server";
      documentation = [ "https://docs.livekit.io" ];
      wantedBy = [ "multi-user.target" ];
      wants = [ "network-online.target" ];
      after = [ "network-online.target" ];

      serviceConfig = {
        LoadCredential = [ "livekit-secrets:${cfg.keyFile}" ];
        ExecStart = utils.escapeSystemdExecArgs [
          (lib.getExe cfg.package)
          "--config=${format.generate "livekit.json" cfg.settings}"
          "--key-file=/run/credentials/livekit.service/livekit-secrets"
        ];
        DynamicUser = true;
        LockPersonality = true;
        MemoryDenyWriteExecute = true;
        ProtectClock = true;
        ProtectControlGroups = true;
        ProtectHostname = true;
        ProtectKernelLogs = true;
        ProtectKernelModules = true;
        ProtectKernelTunables = true;
        PrivateDevices = true;
        PrivateMounts = true;
        PrivateUsers = true;
        RestrictAddressFamilies = [
          "AF_INET"
          "AF_INET6"
          "AF_NETLINK"
        ];
        RestrictNamespaces = true;
        RestrictRealtime = true;
        ProtectHome = true;
        SystemCallArchitectures = "native";
        SystemCallFilter = [
          "@system-service"
          "~@privileged"
          "~@resources"
        ];
        Restart = "on-failure";
        RestartSec = 5;
        UMask = "077";
      };
    };
  };
}
+2 −0
Original line number Diff line number Diff line
@@ -729,11 +729,13 @@ in
  lidarr = handleTest ./lidarr.nix { };
  lightdm = handleTest ./lightdm.nix { };
  lighttpd = runTest ./lighttpd.nix;
  livekit = runTest ./networking/livekit.nix;
  limesurvey = handleTest ./limesurvey.nix { };
  limine = import ./limine { inherit runTest; };
  listmonk = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./listmonk.nix { };
  litellm = runTest ./litellm.nix;
  litestream = handleTest ./litestream.nix { };
  lk-jwt-service = runTest ./matrix/lk-jwt-service.nix;
  lldap = handleTest ./lldap.nix { };
  localsend = handleTest ./localsend.nix { };
  locate = handleTest ./locate.nix { };
+26 −0
Original line number Diff line number Diff line
{
  pkgs,
  lib,
  ...
}:
{
  name = "lk-jwt-service";
  meta.maintainers = [ lib.maintainers.quadradical ];

  nodes.machine = {
    services.lk-jwt-service = {
      enable = true;
      keyFile = pkgs.writers.writeYAML "keys.yaml" {
        key = "f6lQGaHtM5HfgZjIcec3cOCRfiDqIine4CpZZnqdT5cE";
      };
      livekitUrl = "wss://127.0.0.1:8100";
      port = 8000;
    };
  };

  testScript = ''
    machine.wait_for_unit("lk-jwt-service.service")
    machine.wait_for_open_port(8000)
    machine.succeed('curl 127.0.0.1:8000/sfu/get -sLX POST -w "%{http_code}" | grep -q "^400"')
  '';
}
Loading