Warning

Kurento is a low-level platform to create WebRTC applications from scratch. You will be responsible of managing STUN/TURN servers, networking, scalability, etc. If you are new to WebRTC, we recommend using OpenVidu instead.

Acknowledgements

Kurento team gives credit to Signicat for their support that allows us to make it possible continue evolving and developing Kurento Media Server Project.

Signicat logo


Securing Kurento Applications

Securing Application Servers

Configure a Java server to use HTTPS

  • Obtain a certificate. For this, either request one from a trusted Certification Authority (CA), or generate your own one as explained here: Self-Signed Certificates.

  • Convert your PEM certificate to either Java KeyStore (JKS) or PKCS#12. The former is a proprietary format limited to the Java ecosystem, while the latter is an industry-wide used format. To make a PKCS#12 file from an already existing PEM certificate, run these commands:

    openssl pkcs12 \
        -export \
        -in cert.pem -inkey key.pem \
        -out cert.p12 -passout pass:123456
    
    chmod 440 *.p12
    
  • Use the certificate in your application.

    Place your PKCS#12 file cert.p12 in src/main/resources/, and add this to the application.properties file:

    server.ssl.key-store=classpath:cert.p12
    server.ssl.key-store-password=123456
    server.ssl.key-store-type=PKCS12
    
  • Start the Spring Boot application:

    mvn spring-boot:run \
        -Dspring-boot.run.jvmArguments="-Dkms.url=ws://{KMS_HOST}:8888/kurento"
    

Note

If you plan on using a webserver as proxy, like Nginx or Apache, you’ll need to setAllowedOrigins when registering the handler. Please read the official Spring documentation entry for more info.

Configure a Node.js server to use HTTPS

  • Obtain a certificate. For this, either request one from a trusted Certification Authority (CA), or generate your own one as explained here: Self-Signed Certificates.

  • Add the following changes to your server.js, in order to enable HTTPS:

    ...
    var express = require('express');
    var ws      = require('ws');
    var fs      = require('fs');
    var https   = require('https');
    ...
    
    var options =
    {
      cert: fs.readFileSync('cert.pem'),
      key:  fs.readFileSync('key.pem'),
    };
    
    var app = express();
    
    var server = https.createServer(options, app).listen(port, function() {
    ...
    });
    ...
    
    var wss = new ws.Server({
     server : server,
     path : '/'
    });
    
    wss.on('connection', function(ws) {
    
    ....
    
  • Start application

npm start

Configure JavaScript applications to use HTTPS

WebRTC requires HTTPS, so your JavaScript application must be served by a secure web server. You can use whichever one you prefer, such as Nginx or Apache. For quick tests, a very straightforward option is to use the simple, zero-configuration http-server based on Node.js:

curl -sSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install nodejs
sudo npm install -g http-server
  • Obtain a certificate. For this, either request one from a trusted Certification Authority (CA), or generate your own one as explained here: Self-Signed Certificates.

  • Start the HTTPS web server, using the SSL certificate:

    http-server -p 8443 --ssl --cert cert.pem --key key.pem
    

Securing Kurento Media Server

Signaling Plane authorization

You should protect the JSON-RPC API control port (WebSocket port, by default TCP 8888) of your Kurento Media Server instances from unauthorized access from public networks.

The Kurento WebSocket server supports using SSL certificates in order to guarantee secure communications between clients and server; however, at the time no authentication mechanism is provided. Kurento doesn’t reinvent the wheel here including its own mechanism, and instead it relies on layers of security that already exist at the system level. This is something we may add (contributions are welcomed!) but for now here are some tips on how other big players are protecting KMS from unauthorized use.

Think of KMS like you would of a database in a traditional web application; there are two levels:

  1. The application level. We usually call this the “Application Server” of Kurento Media Server. It usually is a web application that uses Client API Reference to access features of Kurento Modules.

  2. The media level (actual audio/video transmissions to/from KMS).

The idea is that nobody unauthorized should be able to access the exchanged media. At the application level we can use all the available techniques used to protect any web server, for example with a custom user/password mechanism. Regarding KMS, the idea is that only the Application Server can access KMS. We can restrict that at the system level, for example using iptables to restrict all incoming WebSocket connections to KMS only from a given host, or a given subnet, similar to this: Iptables Essentials: Common Firewall Rules and Commands (archive). It may be a good idea to have the Application Server running in the same host than the Media Server, and in that case just restrict incoming connections to the same host.

If you need more flexibility, one idea is to restrict KMS connections to the same host using iptables and then implement a WebSocket proxy in the same machine (e.g. using nginx) that has its resources secured, as in NGINX as a WebSocket Proxy (archive) or WebSocket proxying (archive); this way, the Application Server connects to the WebSocket proxy that can indeed be secured, and thus only authenticated users from remote hosts can gain access to KMS.

Signaling Plane security (WebSocket)

With the default configuration, Kurento Media Server will use the ws:// URI scheme for non-secure WebSocket connections, listening on the port TCP 8888. Application Servers (Kurento clients) will establish a WebSocket connection with KMS, in order to control the media server and send messages conforming to the Kurento Protocol.

This is fine for initial stages of application development, but before deploying on production environments you’ll probably want to move to wss:// connections, i.e. using Secure WebSocket, which by default uses the port TCP 8433.

To enable Secure WebSocket, edit the main KMS configuration file (/etc/kurento/kurento.conf.json), and un-comment the following lines:

"secure": {
  "port": 8433,
  "certificate": "cert+key.pem",
  "password": "KEY_PASSWORD"
}

If you use a signed certificate issued by a trusted Certification Authority (CA) such as Verisign or Let’s Encrypt, then you are done. Just skip to the next section: Connecting to Secure WebSocket.

However, if you are going to use an untrusted self-signed certificate (typically during development), there is still more work to do.

Generate your own certificate as explained here: Self-Signed Certificates. Now, because self-signed certificates are untrusted by nature, client browsers and server applications will reject it by default. You’ll need to force all consumers of the certificate to accept it:

  • Java applications. Follow the instructions of this link: SunCertPathBuilderException: unable to find valid certification path to requested target (archive).

    Get InstallCert.java from here: https://github.com/escline/InstallCert.

    You’ll need to instruct the KurentoClient to allow using certificates. For this purpose, create an JsonRpcClient:

    SslContextFactory sec = new SslContextFactory(true);
    sec.setValidateCerts(false);
    JsonRpcClientWebSocket rpcClient = new JsonRpcClientWebSocket(uri, sec);
    KurentoClient kurentoClient = KurentoClient.createFromJsonRpcClient(rpcClient);
    
  • Node.js applications. Take a look at this page: Painless Self Signed Certificates in node.js (archive).

    For a faster but INSECURE alternative, configure Node.js to accept (instead of reject) invalid TLS certificates by default, setting the environment variable flag NODE_TLS_REJECT_UNAUTHORIZED to 0; this will disable the TLS validation for your whole Node.js app. You can set this environment variable before executing your app, or directly in your app code by adding the following line before performing the connection:

    process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
    
  • Browser JavaScript. Similar to what happens with self-signed certificates used for HTTPS, browsers also require the user to accept a security warning before Secure WebSocket connections can be established. This is done by directly opening the KMS WebSocket URL: https://{KMS_HOST}:8433/kurento.

Connecting to Secure WebSocket

Now that KMS is listening for Secure WebSocket connections, and (if using a self-signed certificate) your Application Server is configured to accept the certificate used in KMS, you have to change the WebSocket URL used in your application logic.

Make sure your application uses a WebSocket URL that starts with wss:// instead of ws://. Depending on the platform, this is done in different ways:

  • Java: Launch with a kms.url property. For example:

    mvn spring-boot:run \
        -Dspring-boot.run.jvmArguments="-Dkms.url=wss://{KMS_HOST}:8433/kurento"
    
  • Node.js: Launch with the ws_uri command-line argument. For example:

    npm start -- --ws_uri="wss://{KMS_HOST}:8433/kurento"
    
  • Browser JavaScript: Application-specific method. For example, using hardcoded values:

    const ws_uri: "wss://" + location.hostname + ":8433/kurento";
    

Media Plane security (DTLS)

WebRTC uses DTLS for media data authentication. By default, if no certificate is provided for this, Kurento Media Server will auto-generate a new self-signed certificate for every WebRtcEndpoint instance.

Alternatively, an already existing certificate can be provided to be used for all endpoints. For this, edit the file /etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini and set either pemCertificateRSA or pemCertificateECDSA with a file containing both your certificate (chain) file(s) and the private key. You can generate such file with the cat command:

# Make a single file to be used with Kurento Media Server.
cat cert.pem key.pem >cert+key.pem

Then, configure the path to cert+key.pem.

Setting a custom certificate for DTLS is needed, for example, for situations where you have to manage multiple media servers and want to make sure that all of them use the same certificate for their connections. Some browsers, such as Firefox, require this in order to allow multiple WebRTC connections from the same tab to different KMS instances.