From 4b56c91fce703403b34b3df1e556c791e74ec5c0 Mon Sep 17 00:00:00 2001 From: "J.G. Rubingh" Date: Fri, 15 Oct 2021 11:57:32 +0200 Subject: [PATCH] Update documentation --- README.md | 383 +++++++++----------------- VRE/VRE/{.env.example => env.example} | 0 doc/development.rst | 9 +- doc/documentation.pdf | Bin 1035572 -> 1035543 bytes doc/install.rst | 10 +- docker/project.env | 12 +- docker/project.example.env | 136 ++++++--- run_scheduler.sh | 2 +- 8 files changed, 237 insertions(+), 315 deletions(-) rename VRE/VRE/{.env.example => env.example} (100%) diff --git a/README.md b/README.md index b936cd5..5df91ae 100644 --- a/README.md +++ b/README.md @@ -1,312 +1,179 @@ -# Virtual Research Environment +# VRE Broker [![Build Status](https://drones.web.rug.nl/api/badges/VRE/Broker/status.svg)](https://drones.web.rug.nl/VRE/Broker) -Secure data drop-off & routing software. +Virtual Research Environment Broker is the hart of the [Research Workspace system](/VRE). This is an API that is handling all the actions and requests from either a web interface of direct API. -With this software it is possible to safely upload private and sensitive data like WeTransfer or Dropbox. It is possible to upload single or multiple files at once though a web interface or through an API. +This API is part of the [Research workspace system](/VRE) created by the [Rijksuniversiteit Groningen](https://www.rug.nl). -## Installation +This API is responsible for: + +- Backend for the web interface to the researchers +- Inviting other researchers to your project +- Handles the creation of virtual workspaces (VRW / Openstack) -In order to install this Data drop off project, we need the following packages / software. +More to come ... -- Django -- TUS (The Upload Server) -- NGINX -## Django -We install Django with standard settings. We could run it in Aync way, but then you need some more steps: https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ So for now, we keep it simple. +## Installation + +The Broker is made with the [Django Framework](https://www.djangoproject.com/) in combination with [Django Rest Framework](https://www.django-rest-framework.org/). The installation is pretty straight forward. After this the code is at location `Broker` and during the setup we assume that this is the root folder where you are in. -### Install -Clone the code on `/opt/deploy/data_drop-off` +- First we need a running version of Redis. For Debian/Ubuntu like OS: ```sh -git clone https://git.web.rug.nl/VRE/data_drop-off.git /opt/deploy/data_drop-off +sudo apt install redis-server ``` -Then create a virtual environment +- Checkout this repository: ```sh -cd /opt/deploy/data_drop-off -python3 -m venv . -source bin/activate +git clone https://git.web.rug.nl/VRE/Broker.git ``` -Finally we install the required Python modules -```python -pip install -r requirements +- Create a Python3 virtual environment: +```sh +cd Broker +python3 -m venv venv ``` -This will install all the needed Python modules we need to run this Django project. - -### External libraries: -#### Production -https://gitlab.com/eeriksp/django-model-choices -https://github.com/georgemarshall/django-cryptography -https://github.com/jacobian/dj-database-url -https://github.com/ierror/django-js-reverse - -https://github.com/henriquebastos/python-decouple -https://github.com/ezhov-evgeny/webdav-client-python-3 -https://github.com/dblueai/giteapy -https://pypi.org/project/PyGithub/ - -#### Development -https://github.com/jazzband/django-debug-toolbar - -### Settings -The settings for Django are set in an `.env` file so that you can easily change the environment from production to testing. There is an `.env.example` file that could be used as a template. - -```ini -# A uniquely secret key -SECRET_KEY=@wb=#(f4uc0l%e!5*eo+aoflnxb(@!l9!=c5w=4b+x$=!8&vy%a - -# Disable debug in production -DEBUG=False - -# Allowed hosts that Django does server. Take care when NGINX is proxying infront of Django -ALLOWED_HOSTS=127.0.0.1,localhost - -# Enter the database url connection: https://github.com/jacobian/dj-database-url -DATABASE_URL=sqlite:////opt/deploy/data_drop-off/db.sqlite3 - -# Email settings - -# Mail host -EMAIL_HOST= - -# Email user name -EMAIL_HOST_USER= - -# Email password -EMAIL_HOST_PASSWORD= - -# Email server port number to use -EMAIL_PORT=25 - -# Does the email server supports TLS? -EMAIL_USE_TLS= +- Activate the Python3 virtual environment: +```sh +source venv/bin/activate ``` - -Next we have to make the database structure. If you are using SQLite3 as a backend, make sure the database file **DOES** exist on disk. - +- Install all the required Python3 modules: ```sh -touch /opt/deploy/data_drop-off/db.sqlite3 +pip install -r VRE/requirements.txt ``` - -Then in the Python virtual environment we run the following commands: +- Create a `.env` config file and adjust the **Environment settings**. At least enable `Debug` in development : ```sh -./manage.py migrate -./manage.py loaddata virtual_machine_initial_data -./manage.py createsuperuser -./manage.py collectstatic +cp VRE/VRE/env.example VRE/VRE/.env ``` - -And finally you should be able to start the Django application +- Create the database structure and load some needed data +```sh +VRE/manage.py migrate +VRE/manage.py loaddata virtual_machine_initial_data +VRE/manage.py loaddata university_initial_data +``` +- Create a super user (admin) to login to the admin part of the API +```sh +VRE/manage.py createsuperuser +``` +- Start the Django application ```sh -./manage.py runserver +VRE/manage.py runserver ``` -### TUS -TUS = [The Upload Server](https://tus.io/). This is a resumable upload server that speaks HTTP. This server is a stand-alone server that is running behind the NGINX server. +Now you can enter the Django Admin at `http://localhost:8000/admin/`. If do not see any styles on the page, make sure you have enabled `Debug` or setup [static files for Django](https://docs.djangoproject.com/en/3.2/howto/static-files/) -It is even possible to run a TUS instance on a different location (Amsterdam). As long as the TUS is reachable by the NGINX frontend server, and the TUS server can post webhooks back to the frontend server. +The API can be found at http://localhost:8000/api/swagger/ or http://localhost:8000/api/redoc/ -#### Setup -If needs the package ecnfs* so install that first: `sudo apt install encfs` -The setup is quit simple. This works the same way as Django by using .env file. So start by creating a new settings files based on the example. +## Environment settings -`cp .env.example .env` +In order to get the API running, you need to specify some settings. This is done by creating environment variables with values that are read out by Django during startup. For this you can use a `.env` file or by manually setting bash environment variables. And example env file can be found at `VRE/VRE/env.example` which can be used as a template. + +The location of the env file should be `VRE/VRE/.env` + +[more information can be found here](https://github.com/henriquebastos/python-decouple/) + +### Variables + +All variables have a short explanation above them what they do or used for. ```ini -# TUS Daemon settings -# Change the variable below to your needs. You can also add more variables that are used in the startup.sh script +# A uniquely secret key +# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key +SECRET_KEY=@wb=#(f4uc0l%e!5*eo+aoflnxb(@!l9!=c5w=4b+x$=!8&vy%' -WEBHOOK_URL="http://localhost:8000/datadrops/webhook/" -DROPOFF_API_HAWK_KEY="[ENTER_HAWK_KEY]" -DROPOFF_API_HAWK_SECRET="[ENTER_HAWK_SECRET]" -``` +# Disable debug in production +# https://docs.djangoproject.com/en/dev/ref/settings/#debug +DEBUG=False -You need to create an API user in Django that is allowed to communicatie between the TUS daemon and Django. This can be done by creating a new usre in the Django admin. This will also generate a new token, which is needed. This token can be found at the API -> Tokens page. +# Allowed hosts that Django does server. Use comma separated list Take care when NGINX is proxying in front of Django +# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts +ALLOWED_HOSTS=127.0.0.1,localhost -The default webhook url is: /datadrops/webhook/ +# All internal IPS for Django. Use comma separated list +# https://docs.djangoproject.com/en/dev/ref/settings/#internal-ips +INTERNAL_IPS=127.0.0.1 -Then you can start the upload server by starting with the 'start.sh' script: `./start.sh` +# Enter the database url connection. Enter all parts even the port numbers: https://github.com/jacobian/dj-database-url +# By default a local sqlite3 database is used. +DATABASE_URL=sqlite:///db.sqlite3 -This will start the TUS server running on TCP port 1050. +# The location on disk where the static files will be placed during deployment. Setting is required +# https://docs.djangoproject.com/en/dev/ref/settings/#static-root +STATIC_ROOT= +# Enter the default timezone for the visitors when it is not known. +# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TIME_ZONE +TIME_ZONE=Europe/Amsterdam -#### Data storage -The upload data is stored at a folder that is configured in the TUS startup command. This should be folder that is writable by the user that is running the TUS instance. Make sure that the upload folder is not directly accessible by the webserver. Else files can be downloaded. +# Email settings +# https://docs.djangoproject.com/en/dev/ref/settings/#email-host +# EMAIL_HOST= +# Email user name +# https://docs.djangoproject.com/en/dev/ref/settings/#email-host-user +# EMAIL_HOST_USER= -#### Hooks -The TUS is capable of handling hooks based on uploaded files. There are two types of hooks. 'Normal' hooks and webhooks. It is not possible to run both hook systems at the same time due to the blocking nature of the pre-create hook. So we use the 'normal' hook system. That means that custom scripts are run. Those scripts can then post the data to a webserver in order to get a Webhook functionality with the 'normal' hooks. -At the moment, there is only a HTTP webcall done in the hook system. There is no actual file movement yet. -For now we have used the following hooks: +# Email password +# https://docs.djangoproject.com/en/dev/ref/settings/#email-host-password +# EMAIL_HOST_PASSWORD= -- **pre-create**: This hook will run when a new upload starts. This will trigger the Django server to store the upload in the database, and check if the upload is allowed based on an unique upload url and unique upload code. -- **post-finish**: This hook will run when an upload is finished. And will update the Database/Django with the file size and actual filename (unique) on disk. +# Email server port number to use. Default is 25 +# https://docs.djangoproject.com/en/dev/ref/settings/#email-port +# EMAIL_PORT= -An example of a hook as used in this project. The only changes that should be done is: -- **WEBHOOK_URL**: This is the full url to the Django webhook -Do not change the **HTTP_HOOK_NAME** as this will give errors with Django. +# Does the email server supports TLS? +# https://docs.djangoproject.com/en/dev/ref/settings/#email-use-tls +# EMAIL_USE_TLS= -```python -#!/usr/bin/env python +https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email +DEFAULT_FROM_EMAIL=Do not reply -import sys -import json -import requests +# The sender address. This needs to be one of the allowed domains due to SPF checks +# The code will use a reply-to header to make sure that replies goes to the researcher and not this address +EMAIL_FROM_ADDRESS=Do not reply -# Tus webhook name -HTTP_HOOK_NAME='pre-create' -# Django webserver with hook url path -WEBHOOK_URL='http://localhost:8000/webhook/' +# The Redis server is used for background tasks. Enter the variables below. Leave password empty if authentication is not enabled. +# The hostname or IP where the Redis server is running. Default is localhost +REDIS_HOST=localhost -# Read stdin input data from the TUS daemon -data = ''.join(sys.stdin.readlines()) +# The Redis port number on which the server is running. Default is 6379 +REDIS_PORT=6379 -# Test if data is valid JSON... just to be sure... -try: - json.loads(data) -except Exception as ex: - print(ex) - # Send exit code higher then 0 to stop the upload process on the Tus server - sys.exit(1) +# The Redis password when authentication is enabled +# REDIS_PASSWORD= -# We know for sure that JSON input data is 'valid'. So we post to the webhook for further checking -try: - # Create a webhook POST request with the needed headers and data. The data is the RAW data from the input. - webhook = requests.post(WEBHOOK_URL, headers={'HOOK-NAME':HTTP_HOOK_NAME}, data=data) - # If the POST is ok, and we get a 200 status back, so the upload can continue - if webhook.status_code == requests.codes.ok: - # This will make the Tus server continue the upload - sys.exit(0) +# The amount of connections to be made inside a connection pool. Default is 10 +REDIS_CONNECTIONS=10 -except requests.exceptions.RequestException as ex: - # Webhook post failed - print(ex) +# Enter the full path to the Webbased file uploading without the Study ID part. The Study ID will be added to this url based on the visitor. +DROPOFF_BASE_URL=http://localhost:8000/dropoffs/ -# We had some errors, so upload has to be stopped -sys.exit(1) -``` -This hook uses the same data payload as when TUS would use the Webhook system. So using 'Normal' hooks or using Webhooks with DJANGO should both work out of the box. +# Enter the full url to the NGINX service that is in front of the TUSD service. By default that is http://localhost:1090 +DROPOFF_UPLOAD_HOST=http://localhost:1090 -### NGINX -Install NGINX with LUA support through the package manager. For Ubuntu this would be -```sh -apt install nginx libnginx-mod-http-lua -``` -Also configure SSL to make the connections secure. This is outside this installation scope. - -#### LUA -There is usage of LUA in NGINX so we can handle some dynamic data on the server side. All LUA code should be placed in the folder `/etc/nginx/lua`. - -#### Setup -After installation of the packages, create a symbolic link in the `/etc/nginx/sites-enabled` so that a new VHost is created. - -Important parts of the VHost configuration: -```nginx -lua_package_path "/etc/nginx/lua/?.lua;;"; - -server { - listen 80 default_server; - listen [::]:80 default_server; - - # SSL configuration - # - # listen 443 ssl default_server; - # listen [::]:443 ssl default_server; - # - # Note: You should disable gzip for SSL traffic. - # See: https://bugs.debian.org/773332 - # - # Read up on ssl_ciphers to ensure a secure configuration. - # See: https://bugs.debian.org/765782 - # - # Self signed certs generated by the ssl-cert package - # Don't use them in a production server! - # - # include snippets/snakeoil.conf; - - root /var/www/html; - - # Add index.php to the list if you are using PHP - index index.html; - - server_name localhost; - - # This location is hit when the Tus upload is starting and providing meta data for the upload. - # The actual upload is done with the /files location below - location ~ /files/([0-9a-f]+\-[0-9a-f]+\-[1-5][0-9a-f]+\-[89ab][0-9a-f]+\-[0-9a-f]+)?/ { - set $project_id $1; # Here we capture the UUIDv4 value to use in the Tus metadata manipulation - set $tusmetadata ''; - - # Here we manipulate the metadata from the TUS upload server. - # Now we are able to store some extra meta data based on the upload url. - access_by_lua_block { - local dropoff_tus = require('dropoff_tus'); - local project_metadata = ngx.req.get_headers()['Upload-Metadata']; - if project_metadata ~= nill then - ngx.var.tusmetadata = dropoff_tus.updateTusMetadata(project_metadata,ngx.var.project_id); - end - } - - # Here we update the Tus server metadata so we can add the project uuid to it for further processing - proxy_set_header Upload-Metadata $tusmetadata; - - # Rewrite the url so that the project UUIDv4 is stripped from the url to the Tus server - rewrite ^.*$ /files/ break; - - # Disable request and response buffering - proxy_request_buffering off; - proxy_buffering off; - - client_max_body_size 0; - - # Forward incoming requests to local tusd instance. - # This can also be a remote server on a different location. - proxy_pass http://localhost:1080; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - - proxy_redirect off; - 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; - proxy_set_header X-Forwarded-Proto $scheme; - } - - location ~ /files { - # Disable request and response buffering - proxy_request_buffering off; - proxy_buffering off; - - client_max_body_size 0; - - # Forward incoming requests to local tusd instance - proxy_pass http://localhost:1080; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - - proxy_redirect off; - 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; - proxy_set_header X-Forwarded-Proto $scheme; - } -} +# Which file extensions are **NOT** allowed to be uploaded. By default the extensions exe,com,bat,lnk,sh are not allowed +DROPOFF_NOT_ALLOWED_EXTENSIONS=exe,com,bat,lnk,sh + +# Sentry settings +# Enter the full Sentry DSN string. This should contain a key and a project +SENTRY_DSN= ``` -And there should be a `lua` folder in the `/etc/nginx` folder. +## Background scheduler -In order to test if NGINX is configured correctly run `nginx -t` and it should give an OK message: +For some actions we need a background scheduler system. This system is relaying on Redis, so make sure you have Redis installed. The scheduler can be start with the command: ```sh -nginx: the configuration file /etc/nginx/nginx.conf syntax is ok -nginx: configuration file /etc/nginx/nginx.conf test is successful +./run_scheduler.sh ``` -## Security (not yet inplemented) -It is possible to secure the upload files with PGP encryption. This is done automatically in the Web interface. When you want PGP encryption though API upload, the encryption has to be done before the upload is started. This is a manual action done by the uploader. -So automatic encryption is only available through the Web upload. \ No newline at end of file +This will load the Python3 virtual environment and start the background scheduler. Keep the console open. + +## NGINX +We use NGINX as a proxy in front of the API. This is not mandatory, but can be handy when you have a busy api. + +## VRW Integration +... + + +## Openstack Integration +... \ No newline at end of file diff --git a/VRE/VRE/.env.example b/VRE/VRE/env.example similarity index 100% rename from VRE/VRE/.env.example rename to VRE/VRE/env.example diff --git a/doc/development.rst b/doc/development.rst index 9f76969..7cc1f1e 100644 --- a/doc/development.rst +++ b/doc/development.rst @@ -17,7 +17,7 @@ First we need to checkout the code. .. code-block:: bash - git clone https://git.web.rug.nl/VRE/data_drop-off.git /opt/deploy/VRE + git clone https://git.web.rug.nl/VRE/Broker.git ----- Redis @@ -50,8 +50,6 @@ This will give us a virtual python environment on the location *venv* in the roo source venv/bin/activate pip install -r VRE/requirements.txt - pip install -r demo_portal/requirements.txt - pip install -r tusd/hooks/requirements.txt REST API @@ -71,6 +69,7 @@ Then we can setup and start the REST API server with the following commands. source venv/bin/activate ./VRE/manage.py migrate ./VRE/manage.py loaddata virtual_machine_initial_data + ./VRE/manage.py loaddata university_initial_data ./VRE/manage.py createsuperuser And start with: @@ -84,7 +83,7 @@ Now you can access your REST API server documentation on http://localhost:1337/a There are more settings available to setup. These can be added the to .env file of the REST API. -.. literalinclude:: ../VRE/VRE/.env.example +.. literalinclude:: ../VRE/VRE/env.example :language: bash Scheduler @@ -108,7 +107,7 @@ make sure the TUSD user has the **superuser** status. This is needed. NGINX ----- -NGINX is used on multiple places on the project. This means that we will create multiple virtual domains to get everthing working correctly. +NGINX is used on multiple places on the project. This means that we will create multiple virtual domains to get everything working correctly. **We do not cover SSL setups in this document** diff --git a/doc/documentation.pdf b/doc/documentation.pdf index 769fc773a5b3bb909d4f502fb26aee8e7353a4e1..7c23d5a3fd8364a40ad897c3ff203701eead0c57 100644 GIT binary patch delta 23096 zcmaf)Q*drgw60^@wr$(CZQCpQ;$+44if!ArZQFLvzxO%!r>dX67(KdX)x79_2f8U! zFfCIspb2;m7??RtIT4W>(5)rwxXFdobE)8(sF~~mg`}_XXEz8@B|U4UyMfq5Dk|2vg5|_5eygcKLh7GNxC&4)8N6s=0D%T9NZ&G5 z8E{rakM)FwwKw`r1M_vq63-d=?HCa?g>^uMuV$pe0b4PV!v_4SOhBsL^x|2{X7^}P z%jh2qM4Jd@#r|iRJ*ErF)L84O-CQNf@4Qhqgcm(Jg`ZFd0DCYG9YwUtU2RC++PEz} z>r>yh$jKfDn5Ton4-b*`s&gy;8ex0d%WizwkZIYTIdm56w^O2~{h+)n`EduY`}TQs z#qCk7A?iG%v}(KIDdtVa1?Dv(LqujZn-kPxje^JPr7EClxAHbewU4q67kXi+eG$}_ zeeJ5pg~9j{fD2758-ZDW8Uciq1F|nk_V5)h7D7PoUv`3@1We@%^(HyC*1AzM()9hc zlphU7_W%jnKt;~>6a!41e-tf;9x(*=$KLj2Gml@}WPFp5p_NZiVr8tDg;>Y}8&LSwuO z*Gt;EQn(jvdRBgD278uZH!FA%h+P?TwMMn_jp9yO1**C zGbJZdJTkZp=ayZ{av{Y#`i|u89<7o~3i=)o0AA-$QbCWz(tC$awuxZfYScUfonLge zPMITZM)0j;fS12sxD!j`VARfOEnrdxtL^ZY>I$TJnv8WqpPM*BQUR?;mY34j-&cW; zYcL{P|(a6TN3>r>7C4xEYlhX}_$Pwqr@Ig!}jBj*d?Xe%&<&IJ1(ZP<4N$T;smL zyDix%XsVU}NZDqd8`7x2W9D}})7r$aF?eEVCnQD z-)+U)H|xWER)v=v1Sl5cmRsoXVD^pA_>eM!BSv(XdKS}w@<*i2&W&MDze?NcUFDS! zw$`wyZGPxGFmyx9cpbUo?n{hNaE5{0_^i$3=4bL^yV}Q%#%oXga z$RDAqVSRFNzu-uKHl9O#$G9a2MD{dHc$3Eyy6at{b3XZyGTpra-Q8OioaSR!J+m_L zhJ=*=#NfkinT~HiKrD6zwu;5`)gcA7aU8w@RQBG>xV)O0my)S$8oJP;YirZFjeuM4 zH&`60-``j!2zqSDTO23&l6+ksn_a1!uZJ0>olI-D16rlkH$I%DFl$c$Ik-%5Pf$w( zr6nD^(vn2@az+?Nkn%iw9&nzK+N@kcgOBpDo2)pho>BVRcl!n^)O9p<0epj7I(J!B zwRK0^dWL%&%mz(eb}EfK>|*%1`e2P+Anw=5m9}xJm`xWN>C25a;O`H~ z5W-g$mka1yCqAC9O7^pSM1s2H%$0chBBmaQJK6U5mD4fQr2bEP_@uJf#?EZnV$;xU zIJrW>$x5j_QXDU{#cT#=fs zodI&3r&K5P3Xzqe%PP}PAVUY*^#TaC02AVbgpldh-W*IK<59$9`I<76!g)DG&)HhS zM=N;mv=WYK1UUN&?2YmM&3@s_f5+DLOD}tlO!HTL5;cdm{=7m;D-iiF<@dP}C*ZMJ zJWFieWTfe_SuKF&^uL)70|u$c@=4tL$6fEMd*8yIPIu3JA%SqyOM0N(Ld(Jqo2w&_ z!HNKE9Vo*cTZo3uK##%AX?Dm=t{%u^txLi$pJ|)F=A-K->#hmcZJDJLN0vzxoT(O#-+rs7X~rn_;7gdL2e8obpQ^+m>VQ zU*MFBYEFcS?R4~9s?^i(Ap%tCq~M_WE#x4;mU1g-FxZ%x<9GoPo{<(#6^U*A5y5pi z6k?5SO{sw3jj+=G__3#BwoEAhI5McMj-2JQB)+&r>lb=@Y+ts`B$@9Luiy?s;nvj5Mm~uJh$;v`8e~XXo zabs{JG4AAxU7YsjJf-uF7)G;f(mH{+CNcT#`wc+MO=3542Ms)h)U*?Y?IO2vhl$L( z1WvpD5Lf@7WC{=pPS)%wm7xw0CXsw75<}Gr926O|Ntrll8EBotYCb@T1%<}X=zx&Q<0~Pw9U(uIV4s#HKCCUZzeSfc1HinbFBm>Yu+aY|svin`+72Amb zuu6cf_CF2*$u9!eHIDm4E?}z)Z;AoI0txfYjlTl99X5&v4tVRf4eC{LK^6I zE*czSla$aR<=podC#_ug>NBNfR%68WDJCon$oxddn+S+MaL9MIT?EFC<jEfTNN_>@QIsccl?}zU6RHT%m8Yaa(dz-eS;Of-1c9VOG|NzyW+~r;E!27jPmq+| z4gjxZ%cIV27{BmyNq(+x75G>AnAKthrGB?W3Nbaopi!Upjw_~`kMB6l?n51}NvJ95 zo<41lL8K;)GXXh*UOxz1rY8i~z1#Fk+%VGdrNO*vEZWB(4x21bQY~A?gbV^7*Ht`A|U_ zSF_kZaQgz8!?rIX!;>Olbp3>m@CJY&3A4Y4w>3vM;WOvjeto_fMLgtsd0x+97^=xb zpB+g)Uw^gqd>6CG(wQIrb&roE)%D*zQ7A(Fs{3BMbU{CH&5#|HkTD*!!ODoRAWKJ~ z&?wfbzx7g7$`BBfBrPp!XBudt{39Ev9gF}Q#Vq+el7j^^m>h#gP%zZtI1d`5d zg%6fnbT_%WGd0W``3%h@t1;RD0)kXW`-T>CR@pPUzUL`TA`N!REY{`U5i76)x!Lr7 zX@!22%5AhaTQ=$39O|4l?00Z5v+25mLb2D>ir)u~`#7kjSh)9$dij9xn_j68l+q-w zcKrG{M})%{;?D=~tDPrPL4 zpV&e>R7O!2nvyI!VX-qdx)EOhqs}er%|FH~Sh;?y>Dc1Wmy03{NtQhDa?XsaA!qMG z6tb4I>~c87)2yK!YY71PD-t=&vF=%-QU;5@eM{DfYZVS1(>7U(bFy?MC|znE$tU3> zSxVvs!Swt1`8!}$`a%?2!x{pw#kF_j-ExpQ2d-|^!nNa2dkj+St1kp$&#zO5@@is$ zf=&LxsRi~Ve+%-N^NM9!-D7GJ_Z~cEmG{)7ncw0b@A_#J z#u*3|-F(c&QqVs^<-9S`L;&S8e_a_Ha*-+*o%HFq`OJdqJ81Mg!Vw^2)OUfYU#?=Q zv$aT^hWgY>o8l$!gq-#&(e{`i@yQA3&hz zkk`x)rI5d=#dAWX@!$Wx30x%^IqYn?6VdW2scd&jv`MP0MX=9JF?xr1sOqKdhlw}- zngfeUtQ8lNeseXK*Pe08Uu2uM73e-kWqJT3R0DZ~|d!OpGnBsmyf8z3Eq;K62;G`ANnE(Ny?GLHNgTEX(wtb?L}dNd9} zgBfDaJhn{1O-|<_zhnb1fq{s5PK%m( zP1!`&%B6FqPl0wMtX|Ytv}NSYSs$C-um`@-#srtrPAdR5iSD%^7~$L+Q8}_}NN^6& z{1Wu~Wco2HpT6hySBsbTjmdxWB2E|3O!OXKAvCNOC@jGqaJ~`QYuEjoM+4mcsG%Hq z!!wb|->L@p5Miuagil?#QX5)E)0sPkzJt|MPGj5_39qLcss=6U3LK(TFJF*;;zItT zCciu?#@GBW^gi&U#T5++T&|E`_AU|7ssY^r?d%Vhp|EKp6#A1u zu(P(VDm+jZC>-J%v4asD^f2lB6cA!?Yc;suVJ z#bdl{3#J2s4SF&vIJP`vC=6T1i&d9s2WoC=vQX|RO!nzj7_!Bg&SBQ+J2VTx1kajX z^ws+u#06>_Y7(uq^|$`4E%u%V0%VPGHHvR75UH(1d)_#~yz;4R6TU82MOyf7KI+sf zWiM`QHXtrdU+nYHA;6&nI@4V>8QCzsbQ`lta5{)|ei1u2=amuw$6y8MrO2yR&2=9e zW^M~eAs`_V)~C%kK-G-ZCtL;O;Y`5dwl0XG19tt@|NM1(Dv$URq*>qLQAiV{<4YQc|C7n|y`?2Wvu5uIQsWgnV>INk*7(=!-88((jIofdXp8o7~?shG*+_EGuZf+ zT8Z4>iPXaj_6bR6usetdYu{w2XPFA8-*wT&%hnvOe zjaA(I73qOXHLXc&@s|wMF?v=)P=K*&d}?95U<3s+{L^MBH+pvMNJZR__c!&9o_eU^ z2O%_lix;inn-PruLTLrCwokEt{_@zBhu~ZbaPf8L$jOF-bUS;5UaUmcnHyxUNy$@p z`}B+EEfN;Q*#1dAaz&C9WShVkS1b$tPbk)r*j|Kv)st2u-u0pfPzj##& zz#l+L-eSw$q&Ih(hnN+MIACkdCY2NrAE(6vZIQ^kG<4BCA}YtBCTt)kY)UY=!>U1K zNn6FB&C6a#9ClmvhJk88-9O4>jk$%?pKU_$7H-`Y^EA9sK$e44N^WoHm8PTUjd)$^ zNVFP4<#Yzz33UM=Zba3$*%dCn7^M9G0ps_sRooZJ!e5CuL}emkx>K5U$pX@{lmyk; z-jc*=)a=m%i<9D2myI>`f*mjEGkH>MAXPMDo*|tsm#{9}rf|xi+h6rx$w_q&S~&6& zT}DcyQS7XGKSo$*UrG8n6Pt)V;ALNSj+=B7>Ou>3R7C*90I~vORCCxgo%TbYN{%$Q z>-NJCS)6I&)+_QV)TcpH;e_v%NMGG9FFv!#uGp07wbdN>B4yl}j&%H(8hs4%2dp(* z>JfoGux#r#C2%gw%V=;dNSUme` z8OoqZkro7ItQ4KlvYIC(s9Nq2iy$Hc!<;=rTNVE^&nk=etC z*U$?ph323|q;E&E^U^hp|G+C#EZ(wmr*M#_7l&-;v;+7Rd^yNfbwr1ktM~n93D%yO zOC_KpMFKW7&;q(iPDV>7|$hC!+x z0XguI95JR5^5gCZ%0u=F%-2ny)92~WkC843woSXKU3Up#`j+!|?9c^j$Y8N%b3Pk5 zk}#Q}I(d*#;MW-AiugY0s74fBQzYg+f94C(D{eL83!zdxjcrRB75~H_3vH@bb1;dI54zPH-NT_es%$jQc+5Gs%m3M>rCKm7PO>5qxj~iV2K7 znx5PY+BcY|gM#htxviX9$JB)%Lo7{+5O4ZConr4=TyK8=Qno>yNuor<;OIFK43_51 zECU(&JG}!risGe-0-3c)*23WBJKB4nA`3MV@S8ixhN31^j#}7p~gU%jTuK9HLE&{s)qB&{1W3w(4k}+}~Ier^Ywz@7&8j<@2 zkYyz6ocZu3&`7L1=-Av@&)UCp@wSKWAzl{RvT0yXm2U7}wn<3Ygu`&SgQg-#tY&xM zR&IkieQayaZ#2hhxc^*XWl7+zK4_f!cztp`sbH$$qJX}&MwTa|?p%wd;v$kQWm>zZ zPSSo;x6f_}_v@iw3CTPx4YW-fn*L)C*fM+XbKmshs=fVhpzoGP{xBnRz&6(J!mHgJUDf7F%%}UpCLwH#}2FG{m}Q`2T4TLNC1-J3E>}pqS%StD>-= zuSqH|BpiFJ9$Rbs6E=I6Gv=hCZ1wn*U0idDrYPR!Ci*FW2(ub)Vc`040-p@Pg~B<@ zTHKsGH^246w{P5co(P2~69|s$w~!D;=LLW(anEG_*v=S-)94hH6gT>-y?29$kP# zS8Kd*=^vYlk4qi;mfac6<4OVc(E7)QLIT9Xy#?>Mm(VqgljG@-Ojh$#DC&^7?*2CK z#3$7F*6QpEH++fO`ehd>oS*>-9R=irLrp|0U`&}mwRh*?skd?){0r=*tppvr)iAYz z)o;6pJ-vQzvs~8LI^>=8x&_TamVS5F?p^V2b7R*`iMpaC4=D^dXhB3D$P3sE1$~CH~TC(bwRM|0H_AqUsECs5Ct2 z+6N0El8!Z7J#E`y!-5uNG>gflr*itKVOpZp6hYWAT%$E-WqbjUgi+C52TlEyQgwwi z`Zuy@$5yVy%Abqb1d$OvqTBQ9u28Uy76kx1K!LUV`6ZdmfaF-TGik^7S$K8F`fSM^ zy;&X<3}QJGAqkR|s~|DZkVWoD;o%W|m{g^-`8i|xxGd9?mGEzRNdJ*9nj@qbCO{{g zpWk_KZeCfJqh}Eio4+X0@lMJK_x|T@S^W3nrd_z_)h)s`N2hxcI9&02-i@!T#o)E% z8)qXm+KG3yIcB(MAtF5ly)ctjN`fT`az9NPkr(d70mA#FMv_pF>X>qcgx(_hhwf}L znP12ooNat(mo6$=J1nO$#!v>jks{|3Zw!AdT8pkP@UaCT_j@|AuLn$e3nKQyJ0+2= zNd8-4b-g6DX&S&2e0XcbdT1URZ@*v}0;;OPQ`ok{{}GVLKAm+)6F%N<5Q{7L^#R`L zLLrX9#*DaXZ+ESVBFb2c{pU&}Rv5rnUTC!x!{T3HhM4=I3yroE?(4mewhC8Net|fB z@At`n@HPja{3RVPwWr*jKF`}l_k`)V{m@+8aBba4h2 z)e~Ir=qvCba#}iN1{O9$8k!@rTax@^#S)g+H_V@oPaub&?}HK--pO_VIQEDwArS{G z9A|HTie@KN5W%55DD^>!dS0a46vE!GYv6pH%<*G>=HcmsBAo>=N9L+ECsy{y`~v;- z0S!64~YMO{12%Afc_7dRwiOt!C+8!Zl*NmN?2-u*7kqJ zYB<2H;l3nf8`Vmh;ERXurtvG&)q)+D(Pl6%ZTafZj2Wf=?H4_cN1*rQ1>Ie$!Ctrh=xSr*cyS&9tP~c@`7}ljT*Tb~6>+prZ@V;S z^FpCB+K>RegrOxsoeAmG3dyz7eB!P^sRoT?sP2ah+%&k{BO4 zT>>T6X1ar3$b7oR=pGhMtewUMBPjZ(KH=00&(SYQGqsooll@_9U$J7DFm>O5h@^LG zBks>di+aTlkMwykYV-)RmEFqqD8s6`F-C!fvF`D3!@P+4gmlev35gd#yNe)3Y5?Hh z-Bots)_h_3_cPZ;-%*v5Ka^C3U((#+swOJXqIv=sNzpH!zW7&u+SU@r6x;mO0oPC1 zU6yWQxq=PCuC`hF)N6M$0q)zaJX<4a@P)(EVH?I*#?2rTCJ}1AbrjP=zr3;Z6kkeN zi)l(VB~U$w%h+yxG&vC`unwlYC%{#b4}|9ZN}8;T>I_Z zh!ZGUl=0oAvcc2oI{2toJqhA5XQ;uzH!|Q9=~^|970bxZ)%`b_nMfKXWJWOEym!i7 zy)_5-eMS+sxWVB`NG&T}$)c@!-vBY&#~>56aYgoCk&$0kZZ`*@jQDHxUtDR)U}3pC zTedFDkBlsAyhr@k>tK3Sq6`j*xA-nQ*Y=ox=0||YCSt&k%>o}5hY2GHRUx!_k|lgo zn&SJtf-afd@xoiRJ5!G7#`xb>xottKtV$I{ZV6`6Dp&2KZZY(Y1S;NwwN>(dD7N`F zEZ_&n3%d$<0XYXSwDWIYkF>S>XQDG`^Hy96If)33avX>qL`@VXsQeTfnI$hodh0bE zP6>490-J*_4c2u%0iuY|I&Sh&05k#;a^EpsMq6Zn>tf(I z{eI3-Lg;HsB}#>q*bk0z3Uv=x>PU#_i8Ssn9vKa${<;UCm}0dYzM+_*72ILGD$mW} z)EwB_k&fz-QIgq$yYtt`U^tWlmwOvx)WRmgL9-cMaJUf7YSm!k#8Fo{1fLa(N<<`s zEy6Wzl@kgAQ8vzba6P!u4Hia={P9nu=Kw7s64zo~}#yhC=l0wZQ zh}CsbD+DXRsH(Q5T*fSKuGR080W>ZByIrbG!ZQ3y3$@l zhbh=(5yf6Rgb=41!CxtcR?0BGqhsEQF4Nu4nJx1l$sjSZ5I8ioAoR2nJjUWL#Ee!p z5>5lg%-ZALl~J`j&}=j~3akc8)$e>d&*U(LWqpyw4)H2w`_cF7vebG0q3TRTCYZc5F+BE;8# zTJToDVy8o^OP(zWC?WO-1d-U;x-IJ|NOls}kq@Jf#s*x*Z;76$@h7Vw=q|#stF1!y zLdUKM`^lTSE!QXKv;nI{N!g`kYK_s)0y*6fGc@Rr;20zun3}bS|Kb})(65*M=sy|{ z{0njwq0)*!jiSNp_CIk&A zzINpX)5L@0`RWG%@G7jH{jzM2bzao{t5yHes(SX=eNk?`-4T5ee~vi&%Dq8ior?4! zsC~kgoz{zz3B+@7zMlx;bFX*|^Y zUEuP9GKi{F0kT){Z|&c?5V$4*sI+z_DIr2Z#PFhlECs62c?*EVJuou-D5VkGz@nvLRl;KaZ^1ZCyAl>2 zu%o;Ra{%i5hk{idhyB!GW@cRG_CIBS1T7m)t+FrLa9i7}&u5j;lC-9>8BIw63=%bb z)7nXh6lby6+EQN@OJ{1VHF8;))>t?n7wafS_OQ>~$+k5|P5>WG1OwfL+c@+#{KZXw z8D<_#{FJV0;H)tMy2_l^V3}xYnv^OI=s7s(Civp{Jhx)u{qQmy6iGG4%@L=PDjtdg zAvM7NeyB7jyE~>FBym8)(PefpSHcnjCEQ^>{5s36u4q;KqQ(sK&8U!9+O4xk`I8ge z86Wkhj-E1Jw~qb*NwVzu&)*S7(OJ)_^CMpfUN}D2ua_cL^yrgotZ9}o1oE0&z)SF5@k1*$G*uy@xd`f_=5@p^~05f|2VfI4LOjc z9i#$~iMZsrAcyrhDt%$iqHjJVrpf{aCHgTsHe9*r^g4>K_wL)a`;uBaIJ@`1dac^z z6DyLYP`8jKa8OX4Kxv2;=s6&I0O#6%)-8RSg`WRZh!v{^`@{f2Jh?<5zP;(?60Uv^ezzuQA0)Ej(ve?q4&GSxuwLpibDoBqpT2%jO5@AWw`tUC0 zZ$EW67Zm-0ZVrJr9Xsx%WKt<1ZY+?8K8*KhvBtNI(U%2K2H3ZB`FjnDP=I5aI5p)E z3hA)=gd}=xMbp?ZRL&*h#)wO%%Dp&C1_EqBdIgi1Tib3(4hY)uX`5EH(R3sg?sH?2{T|{IU@XnYhle}>B4k4e zI&UZsI}ggJ*HXCQrEK4a>`t%nXoS4zyR+b?#QvEKBZ7F(A!@B=u5NQN70PndzCh&7 zL8yx;F}5tSB>E2|q823H?ADzxYi6m{xbM&b&$dv2XW~Cbail3lQYIYT2rDw%0A3lb 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 YuD7Stbu$altE#Ii(us;*ylhDKZ#hU5oB#j- delta 23134 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 -# What is the Dropoff Upload host -DROPOFF_UPLOAD_HOST=http://localhost:1080 +# The sender address. This needs to be one of the allowed domains due to SPF checks +# The code will use a reply-to header to make sure that replies goes to the researcher and not this address +EMAIL_FROM_ADDRESS=Do not reply + +# The Redis server is used for background tasks. Enter the variables below. Leave password empty if authentication is not enabled. +# The hostname or IP where the Redis server is running. Default is localhost +REDIS_HOST=redisdb + +# The Redis port number on which the server is running. Default is 6379 +REDIS_PORT=6379 + +# The Redis password when authentication is enabled +REDIS_PASSWORD=redispassword + +# The amount of connections to be made inside a connection pool. Default is 10 +REDIS_CONNECTIONS=10 + +# Enter the full path to the Web based file uploading without the Study ID part. The Study ID will be added to this url based on the visitor. +DROPOFF_BASE_URL=http://localhost:8080/dropoffs/ + +# Enter the full url to the NGINX service that is in front of the TUSD service. By default that is http://localhost:1090 +DROPOFF_UPLOAD_HOST=http://localhost:1090 + +# Which file extensions are **NOT** allowed to be uploaded. By default the extensions exe,com,bat,lnk,sh are not allowed +DROPOFF_NOT_ALLOWED_EXTENSIONS=exe,com,bat,lnk,sh -# What is the full VRE Portal domains -VRE_BROKER_API=http://api-nginx/api # TUS Daemon settings -# Change the variable below to your needs. You can also add more variables that are used in the startup.sh script -# TODO: How to generate this data when starting up? As this user does not exists yet in the database... Should be generated everytime we rebuild... +# Change the required variable below to your needs. +# You can here also overrule the default variables in the startup.sh script + +# This is the full url to the REST API server to post updates during uploads. WEBHOOK_URL=http://api-nginx/api/v1/dropoffs/webhook/ -DROPOFF_API_USER=tusdhook -DROPOFF_API_PASSWORD=doemaarwat -DROPOFF_API_EMAIL=tusd+no-reply@rug.nl -DROPOFF_API_HAWK_KEY=sDl6YmRv -DROPOFF_API_HAWK_SECRET=ExfcR524851PxVmbNzvR7qkoHwzSSJ1A -# VRW API settigs. This is for the VRW client to get data for creating Virtual Workspaces +# The key for the token that is created on the REST API server for communication with the REST API server. +# This token will be created during building the Docker image +DROPOFF_API_HAWK_KEY=dDl6UmRt + +# The secret value that belongs to the token DROPOFF_API_HAWK_KEY. +# This token will be created during building the Docker image +DROPOFF_API_HAWK_SECRET=ExfcR524851PxBmbNzvR7quoHwzSSJ1A + + +# Enter the super API user his key and secret. This is used on the portal side for getting study data on the upload page +# We abuse the TUSD user for this +DROPOFF_API_USER_KEY=sXl7YmRE +DROPOFF_API_USER_SECRET=ExfcG524851PxVmbNzvX7qkoHwzSSJ1A + +# What is the full VRE Portal domains. By default http://localhost:1337/api +VRE_BROKER_API=http://api-nginx/api + +# VRW API settings. This is for the VRW client to get data for creating Virtual Workspaces # The security group that is allowed to access the VRW part of the REST API -# Make sure this variable has the same value of the Django setting: setting.VRW_API_GROUP VRW_API_GROUP=vrw-api # The VRW username for the REST API VRW_API_USER=vrw @@ -79,9 +132,12 @@ VRW_API_PASSWORD=securepassword # The VRW email address for the REST API VRW_API_EMAIL=vrw+no-reply@rug.nl +# The IP number of the Load balancer which may change the IP address based on X-Forwarded-For in NGINX +NGINX_REAL_IP_SOURCE_IP=127.0.0.1 + # The config file that is created by Kubernets which holds all the valid IP addresses that is allowed to overwrite the IP address of the client. Mostly loadbalancers -# Leave emtpy to disable this security measure +# Leave empty to disable this security measure NGINX_REAL_IP_LIST= # The config file that is created by Kubernets which holds all the valid IP addresses to access the admin -# Leave emtpy to disable this security measure -NGINX_VALID_ADMIN_IP_LIST= \ No newline at end of file +# Leave empty to disable this security measure +NGINX_VALID_ADMIN_IP_LIST= diff --git a/run_scheduler.sh b/run_scheduler.sh index 0e922bd..b9ef6b6 100755 --- a/run_scheduler.sh +++ b/run_scheduler.sh @@ -1,7 +1,7 @@ #!/bin/bash # This will start the huey task scheduling: https://huey.readthedocs.io/en/latest/contrib.html#django -# Make sure this script is started in the same folder as where 'clouds.yaml' is. Else Cloud connections will fail +# Make sure this script is started in the same folder as where 'clouds.yaml' is. Else Openstack Cloud connections will fail source venv/bin/activate ./VRE/manage.py run_huey