Standard practice for RTMP is still to have a plain text stream key out on the wires.
I want to acccept RTMPS streams from encoders to NGINX however the RTMP module does not yet have RTMPS.
I'm not interested in all the relay solutions to allow taking an RTMP stream and sending to a place like facebook over RTMPS because the same security flaw is still there because at some point you are passing the keys over plain text.
My question is where can I find the reference specs on RTMPS? I'd like to know what keys are needed to make a proper handshake between an RTMPS source such as OBS and NGINX and then I will use the connection with the RTMP module. Can normal keys and an authority like Let's Encrypt be used on a server so that it can make the handshake with a RTMPS encoder?
I've seen stunnel used to wrap RTMP in TLS. Is it possible to do the reverse -- use stunnel to receive RTMPS and convert back to RTMP for the RTMP module?
Since NGINX is capable of terminating TLS for upstream TCP servers, this should take care of it, using only NGINX (simply added
stream
section to config from @Esa Jokinen):Nginx RTMPS + secret publishing key + IP address based access control
I decided to post this as another answer, as my first answer is still a good explanatory answer to keep, and I also wanted to give credits to Danila Vershinin for pointing out using Nginx's
stream{}
. However, while both these answers increases security by encrypting the contents including the key, they also remove the ability of access control usingallow
/deny
[play|publish] address|subnet|all
of thertmp{}
module.The
stream{}
i.e. proxied TCP has own access control, but (unlikertmp{}
) it can't distinguish publishing from playing: with a singlestream{}
proxy everyone can both publish & play – or is denied from doing neither one. Therefore, an access control using both keys and IP restrictions requires a structure with separate proxies for both publishing and streaming: a separete TCP port for proxying the publishing with the key. The following diagram demonstrates this design:Here, I use the standard port
1935/tcp
for the RTMPS-play and an additional1936/tcp
for the RTMPS-publish. For the internal unencrypted RTMP connections I use similar ports19351
and19361
. The red color represents unencrypted connections & untrusted networks, whereas the green color represents encrypted connections & trusted networks.The proxied TCP now has two (RTMPS) configurations, but both can still use the same certificate:
Likewise, we now need two separate (local loopback) RTMP servers for each application:
The actual IP based access control is done on the
stream{}
section, so only thedeny publish all;
is mandatory for preventing direct publishing using the/live
application. I've added theallow
directives to thertmp{}
section just to clarify (and comment on) the default behaviour of the RTMP access control.UPDATE: This is my original answer that describes pretty well the issues one may face while implementing RTMPS with Nginx. However, I've added an improved version for more fine-tuned access control, and I recommend using the configuration from it, instead.
Yes, this is possible with stunnel, as RTMPS is just a RTMP session wrapped inside a standard TLS session. The examples on the Internet are mostly RTMP→RTMPS i.e. the stunnel is working as a plain text server and TLS client, which is configured with
client = yes
. Without that, theclient
defaults tono
, which is the server mode.The stunnel configuration could look like this:
With this:
1936/tcp
.As the connection to Nginx always comes from the stunnel i.e. from the
127.0.0.1
, you can't use theallow
/deny
directives to limit connection based on IP addresses anymore. This means your access control would be limited to the key, alone, but at the same time it's less of a problem, as it's transmitted encrypted.However, this still causes problems, as you'd push the stream from the same IP than the clients that are using it, but you can't allow them to publish to your stream. Luckily, you don't have to
push
the stream from the application with the key, but you can alsopull
it from the public application (/live
).The following Nginx example configuration takes these considerations into account:
However, this is just an example, so you can and should modify it to fit your exact needs. (Also, I haven't tested this configuration but written it solely based on the documentation, so please feel free to correct, if I got something wrong.)
Not sure if this is valid here but I used as simple SSL Termination as above with proxy protocol to keep client IP Addresses. The RTMP module supports proxy protocol so you can still allow deny by IP address. Done some basic tests and it seems to work just fine, correct messages in the log and deny by IP address worked to.
Maybe I have miss understood but it seems to be doing what I think it should be, i.e. allowing SSL connections via RTMPS and keeping the client IP addresses for access control in the RTMP module.
My stream block looks like this:
And the relevant bits of my RTMP Section: (Note: Direct connections probably wont work but not tried it...suggests this in the blog (see below) but I don't need direct connections).
You can read about it in the RTMP blog http://nginx-rtmp.blogspot.com.
Hope it helps someone and thanks for the answers above as they pointed me in the right direction.
FYI I deny play all as I am pushing out HLS, don't need play or anything else at the moment.