GNU Health/Federation Technical Guide

Introduction edit

 
GNU Health Federation components

In this chapter we will go through the technical aspects behind the GNU Health Federation.

The GNU Health Federation has three main components

  • Nodes
  • Message Server
  • Health Information System / Person Master Index

The HMIS node installation and configuration has already been described in previous chapters. In this chapter we will mainly focus on the Health Information System and the Message / Authentication server (Thalamus).


Health Information System Server (HIS) configuration edit

The Person Master Index and Health Information System are both included in the HIS component of the GNU Health Federation.

Thalamus configuration edit

The Thalamus project provides a RESTful API hub to all the GNU Health Federation nodes. The main functions are:

  1. Message server: A concentrator and message relay from and to the participating nodes in the GNU Health Federation and the GNU Health Information System. Some of the participating nodes include the GNU Health HMIS, mobile PHR applications, laboratories, research institutions and civil offices.
  2. Authentication Server: Thalamus also serves as an authentication and authorization server to interact with the GNUHealth Information System


Technology edit

RESTful API: Thalamus uses a REST (Representional State Transfer) architectural style, powered by Flask technology

Thalamus will perform CRUD (Create, Read, Update, Delete) operations. They will be achieved via the following methods upon resources and their instances.

  • GET : Read
  • POST : Create
  • PATCH : Update
  • DELETE : Delete.

The DELETE operations will be minimal.

JSON: The information will be encoded in JSON format.

Create a new user thalamus with PostgreSQL permissions edit

  • Install PostgreSQL
  • Locate the pg_hba.conf file and add the following line:
local all all trust

If you don't find the file refer to Verify PostgreSQL authentication method

  • Restart PostgreSQL:
$ sudo systemctl restart postgresql.service
  • Give permissions to the newly created thalamus user:
$ sudo su - postgres -c "createuser --createdb --no-createrole --no-superuser thalamus"

Installing Thalamus edit

Thalamus is a flask application, and is pip installable. Using the thalamus operating system user, install Thalamus server locally.

$ pip3 install --user wheel
$ pip3 install --user thalamus
$ pip3 install --user flask-cors


Initializing PostgreSQL for the HIS and Person Master Index edit

The following documentation applies to a demo / test database, that we will call "federation"

1) Create the database

$ createdb federation

2) Locate thalamus

$ pip3 show thalamus
$ cd /path/thalamus/demo/

3) Create the Federation HIS schema

Inside the "demo" directory in Thalamus execute the following SQL script

$ psql -d federation < federation_schema.sql

4) Set the PostgreSQL URI for demo data

In import_pg.py adjust the variable PG_URI to fit your needs. It could be sufficient to just put "dbname='federation'" into psycopg2.connect(...) if your setup fits the default settings.

5) Initialize the Federation Demo database

$ bash ./populate.sh

6) Set the PostgreSQL URI for runtime

Just like in the second step either modify POSTGRESQL_URI in etc/thalamus.cfg or modify psycopg2.connect(...) directly in thalamus.py (not in the demo directory).

At this point you can run and test Thalamus directly from the Flask Werkzeug server,:

$ python3 ./thalamus.py

This is ok for development and testing environments, but for production sites, always run Thalamus from a WSGI container, as described in the next section.

Running Thalamus from a WSGI Container edit

In production settings, for performance reasons you should use a HTTP server. You will find examples on running Thalamus from uWSGI and gunicorn.

Running Thalamus from uWSGI edit

uWSGI is a very robust and fast application that is used as a Web Server Gateway Interface in the context of Thalamus, to forward requests to Thalamus coming from other applications (eg, the Federation Portal or the HMIS node).

First of all install uWSGI and its plugins for HTTP & Python your operating system. For example on Ubuntu:

$ sudo apt install uwsgi uwsgi-plugin-router-access uwsgi-plugin-python3

We have included a uwsgi sample configuration file (etc/thalamus_uwsgi.ini). In order to test uWSGI with HTTP change it into the following:

[uwsgi]
master = 1
# https = 0.0.0.0:8443,/opt/gnuhealth/certs/gnuhealthfed.crt,/opt/gnuhealth/certs/gnuhealthfed.key
http = 0.0.0.0:8080
wsgi-file = thalamus.py 
callable = app 
processes = 4 
threads = 2 
block-size = 32000 
stats = 127.0.0.1:9191
plugins = http,python

To execute Thalamus with the default configuration file:

$ uwsgi --ini etc/thalamus_uwsgi.ini

All these arguments can also be passed to the command line.

Running Thalamus from Gunicorn edit

Note: There are some issues with delay on requests and closing connections when using SSL from the vueJS portal on gunicorn.

Gunicorn supports WSGI natively and it comes as Python package. We have included a simple, default config file (etc/gunicorn.cfg) to run Thalamus from Gunicorn with SSL enabled.

For example, you can run the Thalamus application from Gunicorn as follows. The default configuration file uses secure (SSL) connections:

$ gunicorn --config etc/gunicorn.cfg thalamus:app

Enable SSL for encrypted communication edit

Either get an official certificate or generate a self-signed certificate and private key

$ sudo openssl req -newkey rsa:2048 -new -x509 -days 3650 -nodes -out gnuhealthfed.crt -keyout gnuhealthfed.key

If uWSGI should handle HTTPS, place the certificate (gnuhealthfed.crt) and private key (gnuhealthfed.key) in a directory where the thalamus user has read permissions. Afterwards change etc/thalamus_uwsgi from HTTP to HTTPS using the correct paths. Keep a backup of them in a safe place.

Alternatively keep uWSGI as internal HTTP server and configure a HTTPS reverse proxy. Using apache2 you can create a file thalamus.conf as site with the following content:

<IfModule mod_ssl.c>
<VirtualHost *:443>
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/gnuhealthfed.crt
    SSLCertificateKeyFile /etc/ssl/private/gnuhealthfed.key
    ServerName domain
    ProxyPass / http://your_host:8080/
    ProxyPassReverse / http://your_host:8080/
</VirtualHost>
</IfModule>

Depending on the operating system place this inside /etc/apache2/vhosts.d/ (openSUSE) or /etc/apache2/sites-available/ (Debian/Ubuntu). For the last case enable it afterwards using the a2ensite command. Finally enable some modules and restart apache:

$ sudo a2enmod headers ssl proxy proxy_http
$ sudo systemctl restart apache2.service

Create a systemd service edit

In order to control Thalamus with systemctl and enable it to be activated after startup create a service file thalamus.service with the following content:

[Unit]
Description=Thalamus Server
After=network.target
 
[Service]
User=thalamus
WorkingDirectory=/path/thalamus 
ExecStart=uwsgi --ini etc/thalamus_uwsgi.ini
Restart=on-abort 
Type=notify
KillSignal=SIGQUIT
StandardError=syslog

[Install]
WantedBy=multi-user.target

For the working directory take the path from above for the pip directory.
Put this in the appropriate directory for your operating system: For example /etc/systemd/system/ on Debian/Ubuntu or /usr/lib/systemd/system/ on openSUSE. Afterwards start and enable the service:

$ sudo systemctl start thalamus.service
$ sudo systemctl enable thalamus.service

Using a virtual environment edit

If you want to use a virtual environment create and activate the virtual environment before installing Thalamus:

python3 -m venv /home/thalamus/venv
source /home/thalamus/venv/bin/activate

Besides add the following line to etc/thalamus_uwsgi.ini:

venv = /home/thalamus/venv/

Access Control edit

Thalamus uses a “role” approach related to Authorization. It’s basic, yet versatile.

Each role has the following methods permissions: GET, PATCH, POST, DELETE

The permissions work at endpoint level. Examples of endpoints are "person" or "page" of life.

Following there is sample of the “roles.cfg” file, which shows three main roles: end_user, health_professional and root.


[
    {"role": "end_user", 
     "permissions": {
        "GET": ["person", "book","page","password"],
        "PATCH": ["person","page"],
        "POST": ["page", "password"],
        "DELETE": [],
        "global": "False"
        }
    },

    {"role": "health_professional",
     "permissions": {
        "GET": ["people","person","book","page"],
        "PATCH": ["person", "page"],
        "POST": ["person", "page"],
        "DELETE": [],
        "global": "True"
        }
    },

    {"role": "root",
     "permissions": {
        "GET": ["people","person","book", "page","password"],
        "PATCH": ["person","page"],
        "POST": ["person","page",  "password"],
        "DELETE": ["person","page"],
        "global": "True"
        }
    }
]

Once the user has provided the right credentials, she / he will have the access level to the documents associated to the roles. A user can have one or multiple roles. For example, a health professional usually belongs to two groups:

  • person : she create and read her documents, change her password, etc. Usually her domain is restricted to herself. She can not act on others documents
  • health_professional : She can see her patient medical history, but she can not change her password.


If you executed populate.sh you can use the user/password combination ITAPYT999HON:gnusolidario to test the connection.