Secure your LA infrastructure - AtlasOfLivingAustralia/documentation GitHub Wiki

Draft

Basic measures

Firewall

Ports to open from the outside

Allow basic input traffic 22/80/443 (tcp) from the outside. Restrict external access to solr web interface (port 8983).

Ports to open internally

If you want to restring the internal traffic is more complex. Initially you can open all ports between your VMs and internal IP address as a start while you discover which ports use each services and adapt it to your infrastructure.

Depending on your servers and LA software deployment you should open these TCP ports between your VMs:

  • 22: ssh
  • 80,443: http/s
  • 8009,8080: tomcat
  • 8983: solr
  • 7000, 7001, 9042, 9142, 9160: cassandra
  • 8070, 9000, 9001, 9002: auth (cas, userdetails, etc)
  • 9101: image service (alternative to default 8080)

ufw

If you don't need a complicated firewall configuration you can use this ansible ufw role to quickly configure the iptables in your machines.

Protect you SOLR admin interface

Access to the SOLR admin interface using SOCKs

You can configure a ssh socks proxy to access your solr admin interface

ssh port redirection

When you need to access to the solr admin interface (or similarly to mongo mysql or postgresql ports) from your computer, you can temporarily use ssh port redirection with something like:

ssh -L 8983:127.0.0.1:8983 ubuntu@your-solr-server -N -f

  • -L means: my port 8983 is equals to 127.0.0.1:8983 in my remote solr server
  • -N -f brings this port redirection to the background

but this redirection is only maintained while that ssh connection is running, so it's temporary. (For many use-cases, this is adequate - you create an SSH tunnel for the brief duration of your SOLR administration tasks, then shut it down.) If you like this way to connect to your server's admin ports, you can also use other tools like autossh or sshuttle.

solr admin with apache

If you need something more permanent you can configure a vhost with basic auth like:

<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName index.example.org
ServerAdmin [email protected]
DocumentRoot /srv/index.example.org/www/
<Directory />
Require all granted
</Directory>
<Directory /srv/index.example.org/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
Allow from all
</Directory>
<Location />
  AuthType Basic
  AuthName "Authentication Required"
  AuthUserFile /etc/apache2/passwdfile
  <RequireAny>
    Require env noauth
    Require env REDIRECT_noauth
    Require valid-user
  </RequireAny>
</Location>
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
ProxyRequests Off
ProxyPreserveHost On
ProxyVia full
ProxyPass / http://YOUR_INTERNAL_SOLR_SERVER:8983/
  Include /etc/letsencrypt/options-ssl-apache.conf
  SSLCertificateFile /etc/letsencrypt/live/index.example.org/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/index.example.org/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/index.example.org/chain.pem
</VirtualHost>
</IfModule>

Using nginx to access solr

Some vhost like this should work (adapt it to your server/domain/etc):

server {
    listen 80 ;
    listen [::]:80 ;
    server_name index.l-a.site;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl  http2;
    listen [::]:443 ssl  http2;
    server_name index.l-a.site;
    ssl_certificate /etc/letsencrypt/live/l-a.site/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/l-a.site/privkey.pem;
    ssl_protocols TLSv1.3 TLSv1.2  ;
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
    ssl_prefer_server_ciphers on;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    
    # Force HTTPS was configured, so setting STS value to 1 year (31536000 seconds)
    add_header Strict-Transport-Security "max-age=31536000" always;

    # Secure referrer policy to avoid leaking paths, which can include auth ticket information
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Framing security setting (Reenable using frame_options_header)
    add_header X-Frame-Options DENY always;

    root /srv/l-a.site/www/;
    index index.html;
    client_max_body_size 1024m;

    # If ssl is supported, then push this policy to all users who understand it to trigger HSTS
    add_header Content-Security-Policy upgrade-insecure-requests;

    location / {
        if ($blocked_ip) {
            return 403;
        }
        if ($blocked_user_agent) {
            return 444;
        }
        # proxy_set_header Host $host;
        proxy_set_header Host index.l-a.site;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_read_timeout 10m;
        proxy_pass http://127.0.0.1:8983/;
        auth_basic           "Administrator’s Area";
        auth_basic_user_file /etc/nginx/.htpasswd; 
    }
}

This should be in /etc/nginx/sites-available/solr.conf (for instance) and later do:

ln -s /etc/nginx/sites-available/solr.conf /etc/nginx/sites-enabled/solr.conf
service nginx reload

Configuring a HTTP Basic Authentication.

Allowlist IP address

Some interfaces have a simple IP address allowlist system to allow some IPs to access to the administrative interface, or to use their API, etc:

More info about the /ws/ API allow listing. Take into account that this a insecure measure compared with the use apikeys over https.

Other recommendations

Use fail2ban for prevent brute force in those services (http/s and ssh authentication). If you use wordpress in your node, there is also a good fail2ban wordpress plugin that integrates well with fail2ban.

Other resources

⚠️ **GitHub.com Fallback** ⚠️