Skip to content

Commit

Permalink
SSL everywhere (#403)
Browse files Browse the repository at this point in the history
* ssl everywhere

ssl option in wis2box-ctl

env-variables to share key and cert location

initial docs

mosquitto and nginx ssl/nossl

http://localhost:8999 to http://localhost

* remove placeholder.crt

* add ports in docker-compose.ssl.yml

* remove -nossl suffix for nossl files

* Update wis2box-ctl.py

* Update public-services-setup.rst

---------

Co-authored-by: Tom Kralidis <[email protected]>
  • Loading branch information
maaikelimper and tomkralidis authored Mar 7, 2023
1 parent a7e0f65 commit 2878a39
Show file tree
Hide file tree
Showing 16 changed files with 185 additions and 30 deletions.
4 changes: 2 additions & 2 deletions default.env
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ WIS2BOX_DATADIR=/data/wis2box

# API
WIS2BOX_API_TYPE=pygeoapi
WIS2BOX_API_URL=http://localhost:8999/oapi
WIS2BOX_API_URL=http://localhost/oapi
WIS2BOX_API_BACKEND_TYPE=Elasticsearch
WIS2BOX_API_BACKEND_URL=http://elasticsearch:9200
WIS2BOX_DOCKER_API_URL=http://wis2box-api:80/oapi
Expand All @@ -26,7 +26,7 @@ WIS2BOX_BASEMAP_URL=https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png
WIS2BOX_BASEMAP_ATTRIBUTION=<a href="https://osm.org/copyright">OpenStreetMap</a> contributors

# other
WIS2BOX_URL=http://localhost:8999
WIS2BOX_URL=http://localhost

# access control
WIS2BOX_AUTH_URL=http://wis2box-auth
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.monitoring.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ services:
- GF_ALERTING_ENABLED=true
- GF_USERS_DEFAULT_THEME=dark
- GF_DISABLE_SIGNOUT_MENU=true
- GF_SERVER_ROOT_URL=${WIS2BOX_URL:-http://localhost:8999}/monitoring
- GF_SERVER_ROOT_URL=${WIS2BOX_URL:-http://localhost}/monitoring
- GF_SERVER_SERVE_FROM_SUB_PATH=true
ports:
- 3000:3000
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.override.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
services:
web-proxy:
ports:
- 8999:80
- 80:80

wis2box-ui:
ports:
Expand Down
15 changes: 15 additions & 0 deletions docker-compose.ssl.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
services:
web-proxy:
ports:
- 443:443
volumes:
- ./nginx/nginx-ssl.conf:/etc/nginx/conf.d/ssl.conf
- ${WIS2BOX_SSL_KEY}:/etc/nginx/certs/wis2box.key:ro
- ${WIS2BOX_SSL_CERT}:/etc/nginx/certs/wis2box.crt:ro

mosquitto:
ports:
- 8883:8883
volumes:
- ${WIS2BOX_SSL_KEY}:/tmp/wis2box.key:ro
- ${WIS2BOX_SSL_CERT}:/tmp/wis2box.crt:ro
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ services:
depends_on:
- wis2box-ui
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf

wis2box-ui:
container_name: wis2box-ui
Expand Down
2 changes: 1 addition & 1 deletion docs/source/reference/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,6 @@ Logout of wis2box-management container:
From here, you can run ``python3 wis2box-ctl.py status`` to confirm that containers are running properly.

To explore your wis2box installation and services, visit http://localhost:8999 in your web browser.
To explore your wis2box installation and services, visit http://localhost in your web browser.

.. _`GitHub Actions`: https://github.com/wmo-im/wis2box/blob/main/.github/workflows/tests-docker.yml
18 changes: 18 additions & 0 deletions docs/source/user/public-services-setup.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ To share your data with the WIS2 network, you need to expose some of your wis2bo
* The Global Cache needs to be able to access to your HTTP endpoint to download data published by your wis2box instance
* The Global Broker needs to be able to subscribe to your MQTT endpoint to receive WIS2 notifications published by your wis2box instance

SSL
^^^

To enable HTTPS and MQTTS on your wis2box you can run wis2box with the option `--ssl`:

.. code-block:: bash
python3 wis2box-ctl.py --ssl start
When running wis2box with SSL, you have to set additional environment variables in your dev.env defining the location of your SSL certificate and private key:

.. code-block:: bash
WIS2BOX_SSL_CERT=/etc/letsencrypt/live/example.wis2box.io/fullchain.pem
WIS2BOX_SSL_KEY=/etc/letsencrypt/live/example.wis2box.io/privkey.pem
Please remember to update the ``WIS2BOX_URL`` environment variable after enabling SSL, ensuring your URL starts with `https://`.

Nginx (HTTP)
^^^^^^^^^^^^

Expand Down
2 changes: 1 addition & 1 deletion examples/config/wis2box.extended.dev
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ WIS2BOX_LOGGING_LOGLEVEL=WARNING
WIS2BOX_DATA_RETENTION_DAYS=30

# define the url used by the wis2box-ui and wis2box-api
WIS2BOX_URL=http://localhost:8999
WIS2BOX_URL=http://localhost
WIS2BOX_API_URL=${WIS2BOX_URL}/oapi

# Pub/Sub local broker setup for internal commmunication
Expand Down
81 changes: 81 additions & 0 deletions nginx/nginx-ssl.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
server {
listen 443 ssl;
listen [::]:443 ssl;

ssl_certificate /etc/nginx/certs/wis2box.crt;
ssl_certificate_key /etc/nginx/certs/wis2box.key;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;

add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'WWW-Authenticate' 'Bearer' 'always';

#proxy_read_timeout 300s;
#proxy_connect_timeout 75s;

sendfile on;
gzip on;
gzip_types application/json application/geo+json text/css application/javscript text/plain;
gzip_proxied no-cache no-store private expired auth;
gzip_min_length 1000;

# Proxy requests to the bucket "wis2box-incoming" to MinIO container running on port 9000
# NOTE do not use rewrite, it crashes the upload
location /wis2box-incoming/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;

proxy_connect_timeout 300;
# Default is HTTP/1, keepalive is only enabled in HTTP/1.1
proxy_http_version 1.1;
proxy_set_header Connection "";
chunked_transfer_encoding off;

proxy_pass http://minio:9000;
}
location /data {
# FIXME: derive alias from environment variables
auth_request /auth;
auth_request_set $auth_status $upstream_status;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;

proxy_connect_timeout 300;
# Default is HTTP/1, keepalive is only enabled in HTTP/1.1
proxy_http_version 1.1;
proxy_set_header Connection "";
chunked_transfer_encoding off;

rewrite ^/data(/.*)$ /wis2box-public$1 break;
proxy_pass http://minio:9000;
}
location /oapi {
auth_request /auth;
auth_request_set $auth_status $upstream_status;
proxy_pass http://wis2box-api:80;
}
location / {
proxy_pass http://wis2box-ui:80;
}

location /auth {
internal;
proxy_pass http://wis2box-auth:80/authorize;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header Authorization $http_authorization;
proxy_pass_header Authorization;
}
}

8 changes: 0 additions & 8 deletions nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
worker_processes 1;

events {
worker_connections 128;
}

http {
server {
listen 80;
listen [::]:80;
Expand Down Expand Up @@ -82,4 +75,3 @@ http {
proxy_pass_header Authorization;
}
}
}
2 changes: 1 addition & 1 deletion tests/integration/test_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

DATADIR = Path('.').parent.absolute() / 'tests/data'

URL = 'http://localhost:8999'
URL = 'http://localhost'
API_URL = f'{URL}/oapi'
ID = 'urn:x-wmo:md:mwi:mwi_met_centre:surface-weather-observations'
SESSION = Session()
Expand Down
2 changes: 2 additions & 0 deletions wis2box-broker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ FROM eclipse-mosquitto
RUN mkdir -p /data/wis2box/mosquitto
RUN ln -s /mosquitto /data/wis2box/mosquitto

COPY mosquitto-ssl.conf /mosquitto/config/mosquitto-ssl.conf
COPY mosquitto.conf /mosquitto/config/mosquitto.conf

COPY acl.conf /mosquitto/config/acl.conf
COPY entrypoint.sh /docker-entrypoint.sh

Expand Down
13 changes: 13 additions & 0 deletions wis2box-broker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
#!/bin/sh

if [ -f /tmp/wis2box.crt ]; then
echo "SSL enabled"
echo "setup /mosquitto/certs"
mkdir -p /mosquitto/certs
cp /tmp/wis2box.crt /mosquitto/certs
cp /tmp/wis2box.key /mosquitto/certs
chown -R mosquitto:mosquitto /mosquitto/certs
cp /mosquitto/config/mosquitto-ssl.conf /mosquitto/config/mosquitto.conf
else
echo "SSL disabled"
cp /mosquitto/config/mosquitto.conf /mosquitto/config/mosquitto.conf
fi

echo "Setting mosquitto authentication"
mosquitto_passwd -b -c /mosquitto/config/password.txt $WIS2BOX_BROKER_USERNAME $WIS2BOX_BROKER_PASSWORD
mosquitto_passwd -b /mosquitto/config/password.txt everyone everyone
Expand Down
24 changes: 24 additions & 0 deletions wis2box-broker/mosquitto-ssl.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
log_dest stdout
log_timestamp_format %Y-%m-%dT%H:%M:%S
password_file /mosquitto/config/password.txt
max_queued_messages _WIS2BOX_BROKER_QUEUE_MAX

# ACLs
acl_file /mosquitto/config/acl.conf

## MQTT Listener
listener 1883
protocol mqtt

## WebSockets Listener
listener 8884
protocol websockets

## MQTTs
listener 8883
certfile /mosquitto/certs/wis2box.crt
keyfile /mosquitto/certs/wis2box.key

1 change: 1 addition & 0 deletions wis2box-broker/mosquitto.conf
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ protocol mqtt
## WebSockets Listener
listener 8884
protocol websockets

37 changes: 23 additions & 14 deletions wis2box-ctl.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@
description='manage a compposition of docker containers to implement a wis 2 box',
formatter_class=argparse.RawTextHelpFormatter)

parser.add_argument(
'--ssl',
dest='ssl',
action='store_true',
help='run wis2box with SSL enabled')

parser.add_argument(
'--simulate',
dest='simulate',
Expand Down Expand Up @@ -136,29 +142,32 @@ def make(args) -> None:
:returns: None.
"""

docker_compose_args = DOCKER_COMPOSE_ARGS
if args.ssl:
docker_compose_args +=" --file docker-compose.ssl.yml"
# if you selected a bunch of them, default to all
containers = "" if not args.args else ' '.join(args.args)

# if there can be only one, default to wisbox
container = "wis2box-management" if not args.args else ' '.join(args.args)

if args.command == "config":
run(args, split(f'docker-compose {DOCKER_COMPOSE_ARGS} config'))
run(args, split(f'docker-compose {docker_compose_args} config'))
elif args.command == "build":
run(args, split(
f'docker-compose {DOCKER_COMPOSE_ARGS} build {containers}'))
f'docker-compose {docker_compose_args} build {containers}'))
elif args.command in ["up", "start", "start-dev"]:
run(args, split(
'docker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all-permissions > /dev/null 2>&1'))
run(args, split(
'docker plugin enable loki'))
if containers:
run(args, split(f"docker-compose {DOCKER_COMPOSE_ARGS} start {containers}"))
run(args, split(f"docker-compose {docker_compose_args} start {containers}"))
else:
if args.command == 'start-dev':
run(args, split(f'docker-compose {DOCKER_COMPOSE_ARGS} --file docker-compose.dev.yml up'))
run(args, split(f'docker-compose {docker_compose_args} --file docker-compose.dev.yml up'))
else:
run(args, split(f'docker-compose {DOCKER_COMPOSE_ARGS} up -d'))
run(args, split(f'docker-compose {docker_compose_args} up -d'))
elif args.command == "execute":
run(args, ['docker', 'exec', '-i', 'wis2box-management', 'sh', '-c', containers])
elif args.command == "login":
Expand All @@ -167,15 +176,15 @@ def make(args) -> None:
run(args, split(f'docker exec -u -0 -it {container} /bin/bash'))
elif args.command == "logs":
run(args, split(
f'docker-compose {DOCKER_COMPOSE_ARGS} logs --follow {containers}'))
f'docker-compose {docker_compose_args} logs --follow {containers}'))
elif args.command in ["stop", "down"]:
if containers:
run(args, split(f"docker-compose {DOCKER_COMPOSE_ARGS} {containers}"))
run(args, split(f"docker-compose {docker_compose_args} {containers}"))
else:
run(args, split(
f'docker-compose {DOCKER_COMPOSE_ARGS} down --remove-orphans {containers}'))
f'docker-compose {docker_compose_args} down --remove-orphans {containers}'))
elif args.command == "update":
run(args, split(f'docker-compose {DOCKER_COMPOSE_ARGS} pull'))
run(args, split(f'docker-compose {docker_compose_args} pull'))
elif args.command == "prune":
run(args, split('docker builder prune -f'))
run(args, split('docker container prune -f'))
Expand All @@ -189,17 +198,17 @@ def make(args) -> None:
elif args.command == "restart":
if containers:
run(args, split(
f'docker-compose {DOCKER_COMPOSE_ARGS} stop {containers}'))
f'docker-compose {docker_compose_args} stop {containers}'))
run(args, split(
f'docker-compose {DOCKER_COMPOSE_ARGS} start {containers}'))
f'docker-compose {docker_compose_args} start {containers}'))
else:
run(args, split(
f'docker-compose {DOCKER_COMPOSE_ARGS} down --remove-orphans'))
f'docker-compose {docker_compose_args} down --remove-orphans'))
run(args, split(
f'docker-compose {DOCKER_COMPOSE_ARGS} up -d'))
f'docker-compose {docker_compose_args} up -d'))
elif args.command == "status":
run(args, split(
f'docker-compose {DOCKER_COMPOSE_ARGS} ps {containers}'))
f'docker-compose {docker_compose_args} ps {containers}'))
elif args.command == "lint":
files = walk_path(".")
run(args, ('python3', '-m', 'flake8', *files))
Expand Down

0 comments on commit 2878a39

Please sign in to comment.