在 NGINX-RTMP 上接收 RTMPS 流

joh*_*p34 4 ssl nginx rtmp

RTMP 的标准做法仍然是在线路上使用纯文本流密钥。

我想接受从编码器到 NGINX 的 RTMPS 流,但是 RTMP 模块还没有 RTMPS。

我对所有允许使用 RTMP 流并通过 RTMPS 发送到像 Facebook 这样的地方的中继解决方案不感兴趣,因为相同的安全漏洞仍然存在,因为在某些时候您正在通过纯文本传递密钥。

我的问题是在哪里可以找到有关 RTMPS 的参考规范?我想知道在 OBS 和 NGINX 等 RTMPS 源之间进行正确握手需要哪些密钥,然后我将使用与 RTMP 模块的连接。能否在服务器上使用普通密钥和 Let's Encrypt 之类的权限,以便它可以与 RTMPS 编码器进行握手?

我见过 stunnel 用于在 TLS 中包装 RTMP。是否有可能做相反的事情——使用 stunnel 接收 RTMPS 并转换回 RTMP 模块的 RTMP?

Dan*_*nin 7

由于 NGINX 能够终止上游 TCP 服务器的 TLS,因此应该处理它,仅使用 NGINX(简单地stream从@Esa Jokinen添加到配置的部分):

stream {
    upstream backend {
        server 127.0.0.1:1936;
    }
    server {
        listen 1935 ssl;
        proxy_pass backend;
        ssl_certificate /etc/letsencrypt/live/rtmp.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/rtmp.example.com/privkey.pem;
    }
}

rtmp {
    server {
        listen 127.0.0.1:1936;
        chunk_size 4096;

        application app-secret-stream-key {
            live on;
            record off;
            allow publish 127.0.0.1;  # for streaming through stunnel
            allow play 127.0.0.1;     # for the pull from /live
        }

        application live {
            live on;
            record off;
            deny publish all;         # no need to publish on /live
            allow play all;           # playing allowed

            pull rtmp://127.0.0.1:1936/app-secret-stream-key;
        }
    }
}

http {
    server {
        listen 80;
        server_name rtmp.example.com;

        location ^~ /.well-known/acme-challenge/ {
            root /var/www/letsencrypt;
        }
        location / {
            return 404;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Esa*_*nen 6

Nginx RTMPS + 秘密发布密钥 + 基于 IP 地址的访问控制

\n

我决定将其作为另一个答案发布,因为我的第一个答案仍然是一个值得保留的很好的解释性答案,并且我还想感谢Danila Vershinin指出使用 Nginx 的stream{}. 然而,虽然这两个答案都通过加密包括密钥在内的内容来提高安全性,但它们也消除了使用模块的访问控制的能力。allowdeny [play|publish] address|subnet|allrtmp{}

\n

ie代理stream{}TCP具有自己的访问控制,但(与此不同rtmp{})它无法区分发布和播放:使用单个stream{}代理,每个人都可以发布和播放 \xe2\x80\x93,或者被拒绝执行任何一项操作。因此,使用密钥和 IP 限制的访问控制需要一个具有用于发布和流传输的单独代理的结构:一个单独的 TCP 端口,用于使用密钥代理发布。下图演示了这种设计:

\n

在此输入图像描述

\n

在这里,我使用标准端口1935/tcp进行 RTMPS 播放,并使用附加端口1936/tcp进行 RTMPS 发布。对于内部未加密的 RTMP 连接,我使用类似的端口1935119361。红色代表未加密的连接和不受信任的网络,而绿色代表加密的连接和受信任的网络。

\n

代理 TCP 现在有两个 ( RTMPS ) 配置,但两者仍然可以使用相同的证书:

\n
stream {\n    upstream publish {\n        server 127.0.0.1:19361;\n    }\n    server {\n        listen 1936 ssl;        # additional port for publishing\n        proxy_pass publish;\n        ssl_certificate /etc/letsencrypt/live/rtmp.example.com/fullchain.pem;\n        ssl_certificate_key /etc/letsencrypt/live/rtmp.example.com/privkey.pem;\n\n        allow 192.0.2.1;        # allow publish from this IP\n        allow 192.0.2.0/24;     # -- also supports CIDR notation!\n        deny all;               # deny publish from the rest\n    }\n\n    upstream live {\n        server 127.0.0.1:19351;\n    }\n    server {\n        listen 1935 ssl;        # standard RTMP(S) port\n        proxy_pass live;\n        ssl_certificate /etc/letsencrypt/live/rtmp.example.com/fullchain.pem;\n        ssl_certificate_key /etc/letsencrypt/live/rtmp.example.com/privkey.pem;\n\n        allow all;              # this is public (this is also the default)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

同样,我们现在需要两个独立的(本地环回)RTMP服务器:

\n
rtmp {\n    server {\n        listen 127.0.0.1:19361;\n        chunk_size 4096;\n\n        application secret-key {\n            live on;\n            record off;\n            allow publish 127.0.0.1;  # publishing through rtmps://rtmp.example.com:1936\n            allow play 127.0.0.1;     # for the pull from rtmp://localhost:19351/live\n        }\n    }\n\n    server {\n        listen 127.0.0.1:19351;\n        chunk_size 4096;\n\n        application live {\n            live on;\n            record off;\n            deny publish all;         # no need to publish on /live -- IMPORTANT!!!\n            allow play 127.0.0.1;     # playing through rtmps://rtmp.example.com:1935/live\n\n            pull rtmp://127.0.0.1:19361/secret-key;\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

实际的基于 IP 的访问控制是在该stream{}部分完成的,因此只有deny publish all;强制才能防止使用/live应用程序直接发布。我已将allow指令添加到该rtmp{}部分只是为了澄清(并评论)RTMP 访问控制的默认行为。

\n


Esa*_*nen 5

更新:这是我的原始答案,它很好地描述了在使用 Nginx 实现 RTMPS 时可能面临的问题。但是,我添加了一个改进版本以进行更精细的访问控制,我建议改用它的配置。


是的,这可以通过 stunnel 实现,因为 RTMPS 只是一个封装在标准 TLS 会话中的 RTMP 会话。网上的例子大多是RTMP?RTMPS,即stunnel作为纯文本服务器和TLS客户端工作,配置为client = yes. 没有那个,client默认为no,这是服务器模式

安全通道的配置看起来是这样的:

[rtmps]
accept = 1935
connect = 127.0.0.1:1936
cert=/etc/letsencrypt/live/rtmp.example.com/fullchain.pem
key=/etc/letsencrypt/live/rtmp.example.com/privkey.pem
Run Code Online (Sandbox Code Playgroud)

有了这个:

  • Nginx 应该在本地环回端口上侦听 RTMP 1936/tcp
  • 由于您无法使用 RTMP 更新 Let's Encrypt 证书,因此您可能还需要一个 HTTP 服务器块来进行 HTTP-01 质询。
  • 由于与 Nginx 的连接总是来自 stunnel,即来自127.0.0.1,您不能再使用allow/deny指令来限制基于 IP 地址的连接。这意味着您的访问控制将仅限于密钥,但同时也不是问题,因为它是加密传输的。

    但是,这仍然会导致问题,因为您从与使用它的客户端相同的 IP 推送流,但您不能允许它们发布到您的流。幸运的是,您不必push使用密钥从应用程序传输流,但您也pull可以从公共应用程序 ( /live)传输流。

以下Nginx示例配置考虑了这些因素:

rtmp {
    server {
        listen 127.0.0.1:1936;
        chunk_size 4096;

        application app-secret-stream-key {
            live on;
            record off;
            allow publish 127.0.0.1;  # for streaming through stunnel
            allow play 127.0.0.1;     # for the pull from /live
        }

        application live {
            live on;
            record off;
            deny publish all;         # no need to publish on /live
            allow play all;           # playing allowed

            pull rtmp://127.0.0.1:1936/app-secret-stream-key;
        }
    }
}

http {
    server {
        listen 80;
        server_name rtmp.example.com;

        location ^~ /.well-known/acme-challenge/ {
            root /var/www/letsencrypt;
        }
        location / {
            return 404;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这只是一个示例,因此您可以并且应该对其进行修改以满足您的确切需求。(另外,我还没有测试过这个配置,而是完全根据文档编写的,所以如果我有什么不对的地方,请随时纠正。)