TheHive in Docker

By Adrian | May 7, 2020

Docker is something that i’ve not fully embraced to date, I know, I know… I’m a little late off the mark, but as I get to know Docker more, I can see that it has some worthwhile advantages for me in some of the projects I use and generally getting to know technology is never a bad thing. For instance, why spin up a single server for a service that only has 1 of the 65535 ports used when 99% of the time that server will most likely be idle. Docker gives you the ability to really utilise a host.

Recently I have been taking a look at OpenCTI in Docker and added in Traefik as a reverse proxy, and thought that I would do the same for a Docker/Cortex stack.

The best part about using Traefik is that it handles the Reverse Proxy and all the certificate requirements for you. I am using AWS Route53 via DNS challenge, but you can just as easily use a different DNS provider and/or HTTP challenge.

For this particular setup, there are a few pre-requisites required.

  • A Linux host setup with Docker and Docker-Compose
  • AWS Route53 for DNS challenge
  • Appropriate AWS user account with manage DNS access
  • A populated .env file

The .env Environment File

To avoid hard coding certain items, I am using a .env file that is placed in the same location as the docker-compose.yml file.

Leave the CORTEX_KEY empty at this time. We need to configure a Cortex user first and generate the API key.

CORTEX_KEY=[API KEY OF CORTEX USER]
AWS_HOSTED_ZONE_ID=[YOUR ROUTE53 DNS Zone ID]
AWS_ACCESS_KEY_ID=[AWS ACCESS KEY FOR A ROUTE53 USER]
AWS_SECRET_ACCESS_KEY=[AWS SECRET ACCESS KEY FOR A ROUTE53 USER]
LE_EMAIL=[YOUR EMAIL ADDRESS FOR LETS ENCRYPT]

The docker-compose.yml file

Here is the docker-compose.yml file that I used. It is coded to use the following services:

  • Elasticsearch 6.8.8
  • Cortex 3.0.1
  • TheHive 3.4.1
  • Traefik 2.2

We need to present the Cortex, TheHive and Elasticsearch services to the backend network so they can all talk to each other. We are making the Cortex and TheHive services accessible via Traefik. Any traffic that comes in on port 80 will be automatically redirected to port 443 on the frontend, and Traefik will make the connection to the applications ports (9001 and 9000 respectively).

So we don’t run into issues with Lets Encrypt limits, I start by setting the - --certificatesResolvers.mytlschallenge.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory command for the Traefik service, this way we are testing our setup out with time valid but browser invalid Lets Encrypt certificates. Once you have confirmed that everything is ok, this can be removed to generate fully fledged Lets Encrypt certificates.

Note: There are a few references to example.com which will need to be updated to suit your environment. Once everything is setup, you will be able to access the following hosts in your browser. To avoid any conflicts with my other instances of TheHive/Cortex that I’m currently running, ive added docker into the hostname.

url service
https://lb.example.com Traefik dashboard
https://thehivedocker.example.com TheHive console
https://cortexdocker.example.com Cortex console

Here is the yml file.

version: "3"
services:
  elasticsearch:
    image: elasticsearch:6.8.8
    environment:
      - http.host=0.0.0.0
      - discovery.type=single-node
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    networks:
      - backend

  cortex:
    image: thehiveproject/cortex:3.0.1
    depends_on:
      - elasticsearch
      - traefik
    networks:
      - proxy
      - backend

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.cortexdocker.entrypoints=https"
      - "traefik.http.routers.cortexdocker.rule=Host(`cortexdocker.example.com`)"
      - "traefik.http.routers.cortexdocker.service=cortexdocker"
      - "traefik.http.routers.cortexdocker.tls=true"
      - "traefik.http.services.cortexdocker.loadbalancer.server.port=9001"
      - "traefik.http.routers.cortexdocker.tls.certresolver=mytlschallenge"

      - "traefik.http.routers.cortexdocker_http.entrypoints=http"
      - "traefik.http.routers.cortexdocker_http.rule=Host(`cortexdocker.example.com`)"
      - "traefik.http.routers.cortexdocker_http.middlewares=traefik-redirectscheme"
      - "traefik.http.middlewares.traefik-redirectscheme.redirectscheme.scheme=https"

  thehive:
    image: thehiveproject/thehive:3.4.1
    depends_on:
      - elasticsearch
      - cortex
      - traefik
    command:
      --cortex-port 9001
      --cortex-key ${CORTEX_KEY}
    networks:
      - proxy
      - backend

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.thehivedocker.entrypoints=https"
      - "traefik.http.routers.thehivedocker.rule=Host(`thehivedocker.example.com`)"
      - "traefik.http.routers.thehivedocker.service=thehivedocker"
      - "traefik.http.routers.thehivedocker.tls=true"
      - "traefik.http.services.thehivedocker.loadbalancer.server.port=9000"
      - "traefik.http.routers.thehivedocker.tls.certresolver=mytlschallenge"

      - "traefik.http.routers.thehivedocker_http.entrypoints=http"
      - "traefik.http.routers.thehivedocker_http.rule=Host(`thehivedocker.example.com`)"
      - "traefik.http.routers.thehivedocker_http.middlewares=traefik-redirectscheme"
      - "traefik.http.middlewares.traefik-redirectscheme.redirectscheme.scheme=https"

  traefik:
    image: traefik:v2.2
    environment:
      - AWS_HOSTED_ZONE_ID=${AWS_HOSTED_ZONE_ID}
      - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
      - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
    restart: always
    container_name: traefik
    ports:
      - "80:80"
      - "443:443"
    command:
      - --api.insecure=true # set to 'false' on production
      - --api.dashboard=true
      - --api.debug=false
      - --log.level=DEBUG
      - --providers.docker=true
      - --providers.docker.swarmMode=false
      - --providers.docker.exposedbydefault=false
      - --providers.docker.network=proxy
      - --entrypoints.http.address=:80
      - --entrypoints.https.address=:443
      - --certificatesResolvers.mytlschallenge.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory # Generates LE test certificates.  Can be removed for production
      - --certificatesResolvers.mytlschallenge.acme.dnsChallenge=true
      - --certificatesResolvers.mytlschallenge.acme.dnsChallenge.provider=route53
      - --certificatesresolvers.mytlschallenge.acme.email=${LE_EMAIL}
      - --certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json

    volumes:
      - "letsencrypt:/letsencrypt"
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - proxy

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.entrypoints=https"
      - "traefik.http.routers.api.rule=Host(`lb.example.com`)"
      - "traefik.http.routers.api.service=api@internal"
      - "traefik.http.routers.api.tls=true"
      - "traefik.http.services.api.loadbalancer.server.port=8080"
      - "traefik.http.routers.api.tls.certresolver=mytlschallenge"

      - "traefik.http.routers.api_http.entrypoints=http"
      - "traefik.http.routers.api_http.rule=Host(`lb.example.com`)"
      - "traefik.http.routers.api_http.middlewares=traefik-redirectscheme"
      - "traefik.http.middlewares.traefik-redirectscheme.redirectscheme.scheme=https"

networks:
  backend:
  proxy:
    external: true

volumes:
  letsencrypt:

With both the .env file and docker-compose.yml file created you can start it by using the following command.

env $(cat .env | grep ^[A-Z] | xargs) docker-compose up -d

# Output
Starting traefik                       ... done
Creating thehivedocker_elasticsearch_1 ... done
Creating thehivedocker_cortex_1        ... done
Creating thehivedocker_thehive_1       ... done

Give the setup a few minutes to start fully before accessing.

Initial Setup

Now that we have clean installations of TheHive and Cortex we need to do a few initial items on each to round it out

TheHive

Access https://thehivedocker.example.com and press Update Database.

thehive-db-migration


Create your admin user

thehive-set-admin-user


Login to TheHive. You will notice in the lower right that the Cortex Brain icon has a red circle. This means that the integration is broken at the moment.

thehive-main-screen-cortex-broken


You can also confirm this by checking the About screen. You should see an AUTH_ERROR. This is normal at this time.

thehive-cortex-integration-broken


Cortex

Access https://cortexdocker.example.com and press Update Database. Note this is identical to the step performed for TheHive.


cortex-db-migration


Create the main orgadmin account. This account is used to manage organizations within Cortex.

cortex-create-orgadmin


Login to Cortex. We need to create a new organization. Press the Add organization button and complete the details.

cortex-create-org


Now we need to create a few users for the new organization. Select Users then Add User from the top right hand side of the page.

Complete the details as follows:

cortex-add-org-user-1

  1. The username
  2. The Fullname of the user
  3. The orginization the user will belong to. Ensure the org you just created is setup
  4. The role the account has. Ensure read, analyze, orgadmin is selected
  5. Press Save.

Once the account has been created, select New Password on the users screen.

cortex-admin-new-password


Create a second user account against the same organization. This time, give it the read, analyze roles. This account will be what we use to connect TheHive to Cortex.

cortex-add-org-user-2

There is no need to set a password for this user, however we need to Create API Key and select Reveal. Next Copy this API key.

Back in our .env file, paste in the Cortex API key value to the CORTEX_KEY variable.

Additional Steps

With the .env file updated with our Cortex API key, we need to rerun Docker-Compose which will detect the changes that have been made.

env $(cat .env | grep ^[A-Z] | xargs) docker-compose up -d

# Output
traefik is up-to-date
thehivedocker_elasticsearch_1 is up-to-date
thehivedocker_cortex_1 is up-to-date
Recreating thehivedocker_thehive_1 ... done

Relogin to TheHive. Integration should now be working.

thehive-main-screen-cortex-working

From here its just a matter of enabling any Analyzers and/or Responders from the Cortex console that are required.