Стандартной практикой для RTMP по-прежнему является наличие ключа потока обычного текста на проводе.
Я хочу принимать потоки RTMPS от кодировщиков к NGINX, однако модуль RTMP еще не имеет RTMPS.
Меня не интересуют все решения для ретрансляции, позволяющие принимать поток RTMP и отправлять его в такое место, как facebook, через RTMPS, потому что та же проблема безопасности все еще существует, потому что в какой-то момент вы передаете ключи по обычному тексту.
У меня вопрос: где я могу найти эталонные спецификации RTMPS? Я хотел бы знать, какие ключи необходимы для правильного рукопожатия между источником RTMPS, таким как OBS и NGINX, а затем я буду использовать соединение с модулем RTMP. Можно ли использовать на сервере обычные ключи и такой авторитет, как Let's Encrypt, чтобы он мог установить связь с кодировщиком RTMPS?
Я видел stunnel, используемый для обертывания RTMP в TLS. Можно ли сделать обратное - использовать stunnel для получения RTMPS и конвертировать обратно в RTMP для модуля RTMP?
Поскольку NGINX способен завершать TLS для вышестоящих TCP-серверов, это должно позаботиться об этом, используя только 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;
}
}
}
ОБНОВИТЬ: Это мой первоначальный ответ, который довольно хорошо описывает проблемы, с которыми можно столкнуться при реализации RTMPS с Nginx. Однако я добавил улучшенная версия для более точной настройки контроля доступа, и я рекомендую вместо этого использовать конфигурацию из него.
Да, это возможно с помощью stunnel, поскольку RTMPS - это просто сеанс RTMP, заключенный в стандартный сеанс TLS. Примеры в Интернете - это в основном 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
С этим:
1936/tcp
. Поскольку соединение с 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;
}
}
}
Однако это всего лишь пример, поэтому вы можете и должны изменить его в соответствии со своими потребностями. (Кроме того, я не тестировал эту конфигурацию, но написал ее исключительно на основе документации, поэтому, пожалуйста, не стесняйтесь исправлять, если у меня что-то не так.)
Я решил опубликовать это как еще один ответ, так как мой первый ответ по-прежнему является хорошим объяснительным ответом, и я также хотел бы поблагодарить Данила Вершинин для указания использования Nginx stream{}
. Однако, хотя оба этих ответа повышают безопасность за счет шифрования содержимого, включая ключ, они также исключают возможность контроль доступа с помощью allow
/deny
[play|publish] address|subnet|all
из rtmp{}
модуль.
В stream{}
т.е. прокси TCP имеет собственный контроль доступа, но (в отличие от rtmp{}
) он не может отличить публикацию от игры: с одним stream{}
через прокси-сервер каждый может публиковать и воспроизводить - либо ему запрещается делать ни то, ни другое. Следовательно, контроль доступа с использованием обоих ключи и ограничения IP требуется структура с отдельными прокси для публикации и потоковой передачи: отдельный порт TCP для проксирования публикации с ключом. Следующая диаграмма демонстрирует эту конструкцию:
Здесь я использую стандартный порт 1935/tcp
для RTMPS-play и дополнительного 1936/tcp
для RTMPS-публикации. Для внутренних незашифрованных RTMP-соединений я использую аналогичные порты 19351
и 19361
. Красный цвет представляет незашифрованные соединения и ненадежные сети, а зеленый цвет представляет зашифрованные соединения и доверенные сети.
Теперь проксируемый TCP имеет два (RTMPS), но оба могут использовать один и тот же сертификат:
stream {
upstream publish {
server 127.0.0.1:19361;
}
server {
listen 1936 ssl; # additional port for publishing
proxy_pass backend;
ssl_certificate /etc/letsencrypt/live/rtmp.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/rtmp.example.com/privkey.pem;
allow 192.0.2.1; # allow publish from this IP
allow 192.0.2.0/24; # -- also supports CIDR notation!
deny all; # deny publish from the rest
}
upstream live {
server 127.0.0.1:19351;
}
server {
listen 1935 ssl; # standard RTMP(S) port
proxy_pass live;
ssl_certificate /etc/letsencrypt/live/rtmp.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/rtmp.example.com/privkey.pem;
allow all; # this is public (this is also the default)
}
}
Точно так же нам теперь нужны два отдельных (локальный шлейф) RTMP серверы для каждого приложения:
rtmp {
server {
listen 127.0.0.1:19361;
chunk_size 4096;
application secret-key {
live on;
record off;
allow publish 127.0.0.1; # publishing through rtmps://rtmp.example.com:1936
allow play 127.0.0.1; # for the pull from rtmp://localhost:19351/live
}
}
server {
listen 127.0.0.1:19351;
chunk_size 4096;
application live {
live on;
record off;
deny publish all; # no need to publish on /live -- IMPORTANT!!!
allow play 127.0.0.1; # playing through rtmps://rtmp.example.com:1935/live
pull rtmp://127.0.0.1:19361/secret-key;
}
}
}
Фактический контроль доступа на основе IP осуществляется на stream{}
раздел, поэтому только deny publish all;
является обязательным для предотвращения прямой публикации с использованием /live
применение. Я добавил allow
директивы к rtmp{}
раздел, чтобы прояснить (и прокомментировать) поведение управления доступом RTMP по умолчанию.