The aim is to use the capability of RStudio Server available in professional version using free version.
The scenario is: researchers are using RStudio to perform research within
academic network. The network is protected by firewall but as there is a large
number of hosts connected there is no way to ensure, that there would not be an
attacker from within or from the outside (while, for example, using vulnerability of one of
the network clients).
In order to encrypt the communication between the RStudio
server and the client machine, I used a simple, yet effective trick of proxying
SSL traffic.
In my case I use certificates that I generated then signed them with our organisation wildcard key. You can use self-signed certificates or Let's Encrypt. Configuration needed to use Let's Encrypt is shown in this example:
https://certbot.eff.org/lets-encrypt/centosrhel7-nginx
In my case I use certificates that I generated then signed them with our organisation wildcard key. You can use self-signed certificates or Let's Encrypt. Configuration needed to use Let's Encrypt is shown in this example:
https://certbot.eff.org/lets-encrypt/centosrhel7-nginx
The the following diagram describes the idea behind this scenario:
I achieved similar goal using APACHE 2 with its proxy
module, this guide is fairly good, shows the set-up for port 443 though:
To set this up on a standard HTTPS port (443) is easy enough
and does not require much attention here as it might be discovered on the web,
it was described in few places, however, I wanted to redirect RStudio server to
non-standard port, as I wanted to utilise port 443 for other services.
Basic set-up is well
described here:
and here:
https://www.linode.com/docs/development/r/how-to-deploy-rstudio-server-using-an-nginx-reverse-proxy/
Once we have RStudio Server and nginx installed we need to
look at the config files:
/etc/rstudio/rserver.conf
And add this line in order to make RStudio available only on
localhost and not available from the network through http call:
www-address=127.0.0.1
Then we need to go into nginx config directory and open its
config file located here:
/etc/nginx/nginx.conf
server {
# define the port on which you will connect from client browser:
listen 9999 ssl http2 default_server;
listen [::]:9999 ssl http2 default_server;
server_name our-example-server.com;
root /usr/share/nginx/html;
# use your certificates, use TLS, do not use SSL
ssl_certificate "/etc/pki/tls/certs/our-example-server.com.crt"; ssl_certificate_key "/etc/pki/tls/private/our-example-server.com.key"; ssl_session_cache shared:SSL:1m; ssl_session_timeout 10m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://localhost:8787/;
# below is the real trick that makes it work on non standard port on the whole site:
proxy_redirect http://localhost:8787/ https://our-example-server.com:9999/;
proxy_http_version 1.1;
proxy_ssl_certificate "/etc/pki/tls/certs/our-example-server.com.crt";
proxy_ssl_certificate_key "/etc/pki/tls/private/our-example-server.com.key";
# Each new SSL connection requires a full SSL handshake between the client and server, which is quite CPU-intensive.
# To have NGINX proxy previously negotiated connection parameters and use a so-called abbreviated handshake:
proxy_ssl_session_reuse on;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 20d;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# this is also very important
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
Since I still use original iptables (I found them easier to manage
with my very complicated Docker Swarm Mode cluster), you would need to open
that non-standard port for proxy. Put this in your INPUT chain:
-A INPUT -p tcp -m state -m tcp -s 192.168.10.0/24 --dport 9999 --state NEW -j ACCEPT
This way, you can also implement another feature which is not
available in free version of RStudio Server, which is client IP restriction, the
above example just shows one rule which is applied to the whole subnet
192.168.10.0, but you can widen it or narrow down even to single IP addresses,
like for example 192.168.10.12/32.
The firewalld would look like this:
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.10.0" service name="distinct" accept'where name="distinct" is the name matched to the port according to /etc/services file.
The last thing you need to do, is to permit nginx to work on port
9999, or whatever port you chose. Otherwise SELinux would not allow it.
Since setting SELinux to permissive is a very bad idea and setting it to
disabled is even worse, you would like to execute the following command:
semanage port -a -t http_port_t -p tcp 9999
semanage port -l | grep http_port_t
Please keep in mind, that presented ports, IP addresses and domain
names need to be replaced to your actual ones in order to make above example
work. You would also need to generate encryption keys and replace the example
ones to avoid errors.
Good luck!

No comments:
Post a Comment