Назад | Перейти на главную страницу

Получение потока RTMPS на NGINX-RTMP

Стандартной практикой для 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

С этим:

  • Nginx должен прослушивать RTMP на локальный шлейф, порт 1936/tcp.
  • Поскольку вы не можете обновить сертификат Let's Encrypt с помощью RTMP, вам также может понадобиться блок 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;
        }
    }
}

Однако это всего лишь пример, поэтому вы можете и должны изменить его в соответствии со своими потребностями. (Кроме того, я не тестировал эту конфигурацию, но написал ее исключительно на основе документации, поэтому, пожалуйста, не стесняйтесь исправлять, если у меня что-то не так.)

Nginx RTMPS + секретный ключ публикации + управление доступом на основе IP-адреса

Я решил опубликовать это как еще один ответ, так как мой первый ответ по-прежнему является хорошим объяснительным ответом, и я также хотел бы поблагодарить Данила Вершинин для указания использования 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 по умолчанию.