Securing OpenCTI with HTTPS Using Let's Encrypt and Nginx in Docker

Ensuring the security of your data transmissions is the standard for enterprise platforms. OpenCTI (Open Cyber Threat Intelligence) is a powerful platform that enables organizations to store, organize, and share knowledge about cyber threats. This blog post will guide you through the steps of adding HTTPS to your OpenCTI instance, using Let’s Encrypt for SSL/TLS certificates and Nginx as a reverse proxy, all within a Docker environment managed by Docker Compose.

It is far simpler to set up an Nginx reverse proxy with a trusted certificate in front of your OpenCTI instance rather than trying to enable HTTPS on the OpenCTI web service directly, as you can apply updates to Nginx without disrupting OpenCTI services in production.

This guide is for setting up OpenCTI at "example.com" - for your environment, simply replace this domain name with the one you need to set up. This guide also assumes you have correctly set up DNS records pointing to your OpenCTI instance.

Step 1: Setting Up Docker Compose for OpenCTI and Nginx

To add a reverse proxy and certbot to your OpenCTI instance, add the following to your docker-compose.yml file that defines your OpenCTI instance:

...
  certbot:
    image: certbot/certbot:latest
    container_name: certbot
    volumes:
      - ./data/certbot/www/:/var/www/certbot/:rw
      - ./data/certbot/conf/:/etc/letsencrypt/:rw
  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - 80:80
      - 443:443
    restart: always
    volumes:
      - ./data/nginx/:/etc/nginx/conf.d/:ro
      - ./data/certbot/www:/var/www/certbot/:ro
      - ./data/certbot/conf/:/etc/nginx/ssl:ro
    depends_on:
      - opencti
      - certbot
...

This will create 2 containers: an Nginx web server that loads in configuration from a /data/ folder set up on your local server (relative to where you're storing your docker-compose.ymlfile), and a certbot service to generate and request certificates from LetsEncrypt.

Note: if you're not using a publicly-accessible domain name for your OpenCTI instance, you can omit the certbot container. For internal networks you'll need to request and install a certificate issued by your internal PKI - as there's no single process that covers all environments, we have omitted these instructions. However all you need to do with a valid certificate is put the fullchain.pem file and privkey.pem files into the /data/ folder and adjust the Nginx configuration below to match those paths.

Step 2: Requesting Certificate & Configuring Nginx

To get certbot to be able to validate your hostname to issue a certificate, create an nginx configuration file as /data/nginx/default.conf and put the following port 80 configuration into the file:

server {
    listen 80;
    listen [::]:80;
    server_name example.com;
    server_tokens off;
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
    location / {
        return 301 https://example.com$request_uri;
    }
}

Update your docker containers using docker-compose, and then invoke the certbot container to request your certificate:

docker-compose up -d

docker-compose run --rm certbot certonly --webroot --webroot-path /var/www/certbot/ -d example.com

If certbot requested your certificates correctly, you can now add HTTPS configuration to your nginx config. Update /data/nginx/default.conf with the following to bind port 443 and use the certificate that certbot provisioned:

server {
    listen 80;
    listen [::]:80;
    server_name example.com;
    server_tokens off;
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
    location / {
        return 301 https://example.com$request_uri;
    }
}
server {
    listen 443 default_server ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com;
    ssl_certificate /etc/nginx/ssl/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/live/example.com/privkey.pem;
    location / {
        proxy_cache off;
        proxy_buffering off;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        chunked_transfer_encoding off;
        proxy_pass http://opencti:8080;
    }

Re-load your nginx container for the changes to take effect:

docker-compose exec nginx -s reload

Step 3: Testing Your OpenCTI Instance

Now browse to https://example.com/ to verify that you have a certificate working for your OpenCTI instance!

Conclusion

By following these steps, you have successfully secured your OpenCTI deployment with HTTPS using Let's Encrypt and Nginx. This setup not only enhances the security of your OpenCTI instance but also ensures that your communications are encrypted, protecting sensitive data from being exposed.

Timothy Quinn

Timothy Quinn

Managing Director of Congruent Labs