Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Notable features:
- Add direct push of docker images to GitHub Packages
- Consolidated `docker-compose.yml` file
- Workaround VirtioFS bug when running Docker Desktop for Mac
- stunnel service for TLS wrapping of plaintext services, such as Redis
- ... and many others

The underlying spirit of this project is to allow "repeatable deployments", and all pull requests in this direction will be merged post-haste.
Expand Down Expand Up @@ -374,6 +375,10 @@ The process is *NOT* battle-tested, so it is *NOT* to be followed uncritically.
docker compose up
```

## stunnel service

See [here](/docs/stunnel-guide.md)

## Troubleshooting

- Make sure you run a fairly recent version of Docker and Docker Compose (if in doubt, update following the steps outlined in <https://docs.docker.com/engine/install/ubuntu/>)
Expand Down
2 changes: 2 additions & 0 deletions core/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ FROM php-base
php8.4-gd \
php8.4-fpm \
php8.4-zip \
stunnel4 \
unzip \
zip \
curl \
Expand Down Expand Up @@ -275,6 +276,7 @@ FROM php-base
php8.4-fpm \
php8.4-zip \
php8.4-ldap \
stunnel4 \
libmagic1 \
libldap-common \
librdkafka1 \
Expand Down
3 changes: 3 additions & 0 deletions core/files/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ export NGINX_X_FORWARDED_FOR=${NGINX_X_FORWARDED_FOR:-false}
export NGINX_SET_REAL_IP_FROM=${NGINX_SET_REAL_IP_FROM}
export NGINX_CLIENT_MAX_BODY_SIZE=${NGINX_CLIENT_MAX_BODY_SIZE:-50M}

export STUNNEL=${STUNNEL:-false}
export STUNNEL_CONFIG=${STUNNEL_CONFIG}

export SUPERVISOR_HOST=${SUPERVISOR_HOST:-127.0.0.1}
export SUPERVISOR_USERNAME=${SUPERVISOR_USERNAME:-supervisor}
export SUPERVISOR_PASSWORD=${SUPERVISOR_PASSWORD:-supervisor}
Expand Down
15 changes: 15 additions & 0 deletions core/files/etc/supervisor/conf.d/40-stunnel.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[program:stunnel]
directory=/tmp
command=/usr/bin/stunnel %(ENV_STUNNEL_CONFIG)s
process_name=%(program_name)s_%(process_num)02d
numprocs=1
autostart=%(ENV_STUNNEL)s
autorestart=true
redirect_stderr=false
stderr_logfile=/var/www/MISP/app/tmp/logs/stunnel-errors.log
stdout_logfile=/var/www/MISP/app/tmp/logs/stunnel.log
stderr_logfile_backups=2
stderr_logfile_maxbytes=5MB
stdout_logfile_backups=2
stdout_logfile_maxbytes=5MB
user=root
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ services:
- "S3_ENDPOINT=${S3_ENDPOINT}"
- "S3_ACCESS_KEY=${S3_ACCESS_KEY}"
- "S3_SECRET_KEY=${S3_SECRET_KEY}"
# stunnel settings
- "STUNNEL=${STUNNEL}"
- "STUNNEL_CONFIG=${STUNNEL_CONFIG}"
# supervisor settings
- "SUPERVISOR_HOST=${SUPERVISOR_HOST}"
- "SUPERVISOR_USERNAME=${SUPERVISOR_USERNAME}"
Expand Down
50 changes: 50 additions & 0 deletions docs/examples/stunnel/redis/docker-compose.override.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
services:
misp-core:
volumes:
- ./misp_custom:/custom
redis:
command: |
sh -c '
if [ "$${ENABLE_REDIS_EMPTY_PASSWORD:-false}" = "true" ]; then
exec valkey-server \
--port 0 \
--tls-port 6379 \
--tls-cert-file /custom/server-cert.pem \
--tls-key-file /custom/server-key.pem \
--tls-ca-cert-file /custom/ca.pem \
--tls-auth-clients yes
else
exec valkey-server \
--port 0 \
--tls-port 6379 \
--tls-cert-file /custom/client-cert.pem \
--tls-key-file /custom/client-key.pem \
--tls-ca-cert-file /custom/ca.pem \
--tls-auth-clients yes \
--requirepass "$${REDIS_PASSWORD:-redispassword}"
fi
'
healthcheck:
test: |
sh -c '
if [ "$${ENABLE_REDIS_EMPTY_PASSWORD:-false}" = "true" ]; then
valkey-cli \
--tls \
--cert /custom/client-cert.pem \
--key /custom/client-key.pem \
--cacert /custom/ca.pem \
-p $${REDIS_PORT:-6379} \
ping | grep -q PONG || exit 1
else
valkey-cli \
--tls \
--cert /custom/client-cert.pem \
--key /custom/client-key.pem \
--cacert /custom/ca.pem \
-a "$${REDIS_PASSWORD:-redispassword}" \
-p $${REDIS_PORT:-6379} \
ping | grep -q PONG || exit 1
fi
'
volumes:
- ./misp_custom/redis_tls:/custom:ro
52 changes: 52 additions & 0 deletions docs/examples/stunnel/redis/misp_custom/redis_tls/gencerts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/bash

# --- CA ---
openssl genrsa -out ca-key.pem 4096

openssl req -x509 -new -nodes \
-key ca-key.pem \
-sha256 -days 3650 \
-subj "/C=AU/ST=VIC/L=Melbourne/O=Example/OU=CA/CN=Example-CA" \
-out ca.pem


# --- SERVER CERT ---
openssl genrsa -out server-key.pem 2048

openssl req -new \
-key server-key.pem \
-subj "/C=AU/ST=VIC/L=Melbourne/O=Example/OU=Server/CN=redis" \
-addext "subjectAltName=DNS:redis,DNS:localhost,IP:127.0.0.1" \
-out server.csr

openssl x509 -req \
-in server.csr \
-CA ca.pem \
-CAkey ca-key.pem \
-CAcreateserial \
-sha256 -days 825 \
-out server-cert.pem \
-extfile <(printf "subjectAltName=DNS:redis,DNS:localhost,IP:127.0.0.1")


# --- CLIENT CERT ---
openssl genrsa -out client-key.pem 2048

openssl req -new \
-key client-key.pem \
-subj "/C=AU/ST=VIC/L=Melbourne/O=Example/OU=Client/CN=client" \
-out client.csr

openssl x509 -req \
-in client.csr \
-CA ca.pem \
-CAkey ca-key.pem \
-CAcreateserial \
-sha256 -days 825 \
-out client-cert.pem


# --- PERMS ---
chmod 600 ca-key.pem server-key.pem client-key.pem
chmod 644 ca.pem server-cert.pem client-cert.pem

13 changes: 13 additions & 0 deletions docs/examples/stunnel/redis/misp_custom/stunnel/stunnel.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
foreground = yes
pid = /var/run/stunnel.pid
debug = 3
[elasticache]
client = yes
accept = localhost:6379
connect = redis:6379

cert = /custom/redis_tls/client-cert.pem
key = /custom/redis_tls/client-key.pem
CAfile = /custom/redis_tls/ca.pem
verify = 1
OCSPrequire = no
100 changes: 100 additions & 0 deletions docs/stunnel-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# MISP stunnel Guide #

This guide provides some basic examples of how to use the [stunnel](https://www.stunnel.org/) functionality provided in the misp-docker image.

## Enabling ##

`template.env` contains two stunnel related variables:
| Variable | Values | Default | Purpose |
| :------------- | :--------------- | :------ | :------------------------------------------------------------------------- |
| STUNNEL | `true`/`false` | `false` | If true will start the stunnel service on container start, via supervisord |
| STUNNEL_CONFIG | File path string | | Must contain a file path to a stunnel config file |

If `STUNNEL` is `true` but `STUNNEL_CONFIG` is unset, empty or otherwise does not point to a config file, supervisord will retry starting the service a few times before failing.

## Configuration ##

You can find the stunnel configuration documentation [here](https://www.stunnel.org/static/stunnel.html), and general examples [here](https://www.stunnel.org/examples.html).

## Example: Redis over TLS ##

This example demonstrates how misp-docker's Redis (Valkey) container might be configured to use TLS, and how to leverage the stunnel functionality to communicate with it over TLS.

The general idea here is that stunnel will expose a plaintext port for the MISP codebase to talk Redis over, which will then be proxied to the `redis` container's TLS speaking port. Traffic across the containers will be via TLS as a result. You could just as easily point to an AWS Elasticache or other external Redis instance with the benefit of TLS encryption.

This example largely builds on [this](https://redis.io/blog/stunnel-secure-redis-ssl/) redis.io blog post.

### Steps: ###

#### Copy the example files into the root of your misp-docker project ####

If you have an existing directory named `misp_custom` or a `docker-compose.override.yml` file already, the below will mess with them. You may wish to manually add these things in that case.

Change into your misp-docker project dir first.

```
cp -r docs/examples/stunnel/redis/misp_custom .
cp docs/examples/stunnel/redis/docker-compose.override.yml .
```

The `docker-compose.override.yml` file will reference the files within the `misp_custom` directory, tell Redis to use TLS key files for TLS communications, and tell the health check to use it as well.

#### Roll some certificates ####

We will do this in the `misp_custom/redis_tls` directory using `gencerts.sh` which were copied from the last step:

```
cd misp_custom/redis_tls
./gencerts.sh
cd ../..
```

You should be left with a directory structure that looks like this:

```
tree misp_custom
misp_custom/
├── redis_tls
│   ├── ca-key.pem
│   ├── ca.pem
│   ├── ca.srl
│   ├── client-cert.pem
│   ├── client.csr
│   ├── client-key.pem
│   ├── gencerts.sh
│   ├── server-cert.pem
│   ├── server.csr
│   └── server-key.pem
└── stunnel
└── stunnel.conf

3 directories, 11 files
```

#### Update .env file with necessary values ####

Edit your .env file so that the following envars are like this:

```
REDIS_HOST=localhost
STUNNEL=true
STUNNEL_CONFIG=/custom/stunnel/stunnel.conf
```

#### Bring up the compose project ####

```
docker compose up -d
```

You should now have TLS wrapped Redis, where the client and server are authenticating each other.

Check the Administration -> Server Settings & Maintenance -> Diagnostics tool for system status.

### Troubleshooting ###

Places to look for clues if you run into trouble:

* stunnel log files will appear in in the `logs` dir as `stunnel.log` and `stunnel-errors.log`
* Redis/valkey log output can be found in the `redis` container
* Supervisord log output can be found in the `misp-core` container
10 changes: 7 additions & 3 deletions template.env
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ SYNCSERVERS_1_PULL_RULES=

# optional and used to set mysql db TLS configuration
# MYSQL_TLS=true
# MYSQL_TLS_CA=/custom/files/tls/misp_ca.pem
# MYSQL_TLS_CERT=/custom/files/tls/misp_cert.cert
# MYSQL_TLS_KEY=/custom/files/tls/misp_key.key
# MYSQL_TLS_CA=/custom/files/tls/mysql_ca.pem
# MYSQL_TLS_CERT=/custom/files/tls/mysql_pubcert.cert
# MYSQL_TLS_KEY=/custom/files/tls/mysql_privkey.key

# optional and used to set redis
# REDIS_HOST=
Expand Down Expand Up @@ -252,6 +252,10 @@ SYNCSERVERS_1_PULL_RULES=
# S3_ACCESS_KEY=
# S3_SECRET_KEY=

# stunnel configuration for arbitrary proxying of local plaintext connections to tls endpoints
# STUNNEL=false
# STUNNEL_CONFIG=/custom/files/stunnel/stunnel.conf

## MISP-Guard
# Configure rules in ./guard/config.json.
# Requires restart of misp-guard container after changes.
Expand Down