Reverse Proxy
Configuration du proxy inverse¶
Un proxy inverse est un serveur proxy qui agit pour le compte d'un autre serveur. L'utilisation d'un proxy inverse en combinaison avec un conteneur de servlets n'est pas obligatoire mais présente de nombreux avantages :
-
Les requêtes peuvent être mises en correspondance et transmises à plusieurs conteneurs de servlets. Cela rend le système plus flexible et facilite l'exécution de plusieurs instances DHIS2 sur un même serveur. Cela permet également de modifier la configuration du serveur interne sans affecter les clients.
-
L'application DHIS2 peut être exécutée dans un mode autre que super-utilisateur sur un port autre que 80, ce qui réduit la vulnérabilité face au piratage de sessions.
-
Le proxy inverse peut agir comme un serveur SSL unique et être configuré pour inspecter les demandes de contenu malveillant, enregistrer les demandes et les réponses et fournir des messages d'erreur non sensibles, ce qui va améliorer la sécurité.
Configuration de base de Nginx¶
Nous vous recommandons d'utiliser nginx comme proxy inverse en raison de sa faible empreinte mémoire et sa facilité d'utilisation. Pour l'installer, appelez la commande suivante :
sudo apt-get install -y nginx
nginx peut maintenant être lancé, rechargé et arrêté avec les commandes suivantes :
sudo /etc/init.d/nginx start
sudo /etc/init.d/nginx reload
sudo /etc/init.d/nginx stop
Maintenant que nous avons installé nginx, nous allons continuer la configuration normale du proxy des requêtes vers notre instance Tomcat, qui, nous le supposons, s'exécute avec l'adresse http://localhost:8080. Pour configurer nginx, vous pouvez ouvrir le fichier de configuration en appelant :
sudo nano /etc/nginx/nginx.conf
La configuration de nginx se fait autour d'une hiérarchie de blocs représentant le http, le serveur et l'emplacement, où chaque bloc hérite des paramètres des blocs parents. L'extrait suivant va configurer nginx pour qu'il passe (redirige) les requêtes du port 80 (qui est le port sur lequel nginx écoute par défaut) vers notre instance Tomcat. Ajoutez la configuration suivante dans le fichier nginx.conf :
http {
gzip on; # Enables compression, incl Web API content-types
gzip_types
"application/json;charset=utf-8" application/json
"application/javascript;charset=utf-8" application/javascript text/javascript
"application/xml;charset=utf-8" application/xml text/xml
"text/css;charset=utf-8" text/css
"text/plain;charset=utf-8" text/plain;
server {
listen 80;
client_max_body_size 10M;
# Proxy pass to servlet container
location / {
proxy_pass http://localhost:8080/;
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-Proto http;
proxy_buffer_size 128k;
proxy_buffers 8 128k;
proxy_busy_buffers_size 256k;
proxy_cookie_path ~*^/(.*) "/$1; SameSite=Lax";
}
}
}
Vous pouvez désormais accéder à votre instance DHIS2 à l'adresse http://localhost. Etant donné que le proxy inverse a été installé, nous pouvons améliorer la sécurité en configurant Tomcat pour qu'il n'écoute que les connexions locales. Dans /conf/server.xml, vous pouvez ajouter un attribut address avec la valeur localhost à l'élément Connector pour HTTP 1.1 comme suit :
<Connector address="localhost" protocol="HTTP/1.1" />
Activation de SSL avec nginx¶
Afin d'améliorer la sécurité, il est recommandé de configurer le serveur qui exécute DHIS2 de manière à ce qu'il communique avec les clients via une connexion cryptée et de s'identifier auprès des clients à l'aide d'un certificat de confiance. Ceci peut être réalisé via SSL qui est un protocole de communication cryptographique fonctionnant au-dessus de TCP/IP. Tout d’abord, installez la bibliothèque openssl requise :
sudo apt-get install -y openssl
Pour configurer nginx de manière à ce qu'il utilise SSL, vous aurez besoin d'un certificat SSL approprié provenant d'un fournisseur SSL. Le coût d'un certificat varie en fonction de la puissance du cryptage. Un certificat abordable de [Rapid SSL Online] (http://www.rapidsslonline.com) devrait répondre à la plupart des besoins. Pour générer le CSR (demande de signature de certificat), vous pouvez appeler la commande ci-dessous. À l'invite du Nom commun, entrez le nom du domaine qualifié pour le site que vous sécurisez.
openssl req -new -newkey rsa:2048 -nodes -keyout server.key -out server.csr
Après avoir reçu vos fichiers de certificat (.pem ou .crt), vous devez les placer avec le fichier server.key généré, dans un emplacement accessible par nginx. Le répertoire où se trouve votre fichier nginx.conf peut servir d'emplacement à cet effet.
Vous trouverez ci-dessous un bloc serveur nginx où les fichiers de certificats sont nommés server.crt et server.key. Étant donné que les connexions SSL se font généralement sur le port 443 (HTTPS), nous transmettons les requêtes sur ce port (443) à l'instance DHIS2 qui s'exécute à l'adresse http://localhost:8080. Le premier bloc serveur réécrira toutes les requêtes connectées au port 80 et forcera l'utilisation de HTTPS/SSL. Ceci est également nécessaire car DHIS2 utilise beaucoup de redirections en interne, lesquelles doivent être transmises pour pouvoir utiliser HTTPS. N'oubliez pas de remplacer \<server-ip> par l'IP de votre serveur. Ces blocs doivent remplacer celui de la section précédente.
http {
gzip on; # Enables compression, incl Web API content-types
gzip_types
"application/json;charset=utf-8" application/json
"application/javascript;charset=utf-8" application/javascript text/javascript
"application/xml;charset=utf-8" application/xml text/xml
"text/css;charset=utf-8" text/css
"text/plain;charset=utf-8" text/plain;
# HTTP server - rewrite to force use of SSL
server {
listen 80;
rewrite ^ https://<server-url>$request_uri? permanent;
}
# HTTPS server
server {
listen 443 ssl;
client_max_body_size 10M;
ssl on;
ssl_certificate server.crt;
ssl_certificate_key server.key;
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers RC4:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Proxy pass to servlet container
location / {
proxy_pass http://localhost:8080/;
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-Proto https;
proxy_buffer_size 128k;
proxy_buffers 8 128k;
proxy_busy_buffers_size 256k;
proxy_cookie_path ~*^/(.*) "/$1; SameSite=Lax";
}
}
}
Notez la dernière valeur de l'en-tête https qui est nécessaire pour informer le conteneur de servlets que la requête arrive par HTTPS. Pour que Tomcat produise correctement les en-têtes d'URL d'Emplacement en utilisant HTTPS, vous devez également ajouter deux autres paramètres au Connector dans le fichier server.xml de Tomcat :
<Connector scheme="https" proxyPort="443" />
Activation de la mise en cache avec nginx¶
Les demandes de rapports, de graphiques, de cartes et d'autres ressources liées à l'analyse mettent souvent un certain temps avant de recevoir des réponses et peuvent utiliser une grande partie des ressources du serveur. Afin d'améliorer les temps de réponse, de réduire la charge sur le serveur et d'éviter d'éventuels temps d'arrêt, nous pouvons introduire un proxy de cache dans notre configuration de serveur. Le contenu mis en cache sera stocké dans le répertoire /var/cache/nginx, et jusqu'à 250 Mo de stockage y seront alloués. Nginx créera ce répertoire automatiquement.
http {
..
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=dhis:250m inactive=1d;
server {
..
# Proxy pass to servlet container and potentially cache response
location / {
proxy_pass http://localhost:8080/;
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-Proto https;
proxy_buffer_size 128k;
proxy_buffers 8 128k;
proxy_busy_buffers_size 256k;
proxy_cookie_path ~*^/(.*) "/$1; SameSite=Lax";
proxy_cache dhis;
}
}
}
Important
Sachez qu'un cache côté serveur court-circuite les fonctions de sécurité de DHIS2 dans le sens où les requêtes qui atteignent le cache côté serveur seront servies directement à partir du cache hors de contrôle de DHIS2 et du conteneur de servlets. Cela signifie que les URL des requêtes peuvent être devinées de même que les rapports récupérés dans le cache par des utilisateurs non autorisés. Par conséquent, si vous collectez des informations sensibles, la mise en place d'un cache côté serveur n'est pas recommandée.
Limitation de débit avec nginx¶
Certains appels d'API web dans DHIS 2, tels que les API d'analyses, nécessitent beaucoup de calculs. Par conséquent, il est préférable de limiter le débit de ces API afin d'équilibrer l'utilisation des ressources du serveur par les utilisateurs du système. La limitation de débit peut être effectuée avec nginx. Il existe plusieurs approches pour effectuer la limitation de débit et ceci est destiné à documenter l'approche basée sur nginx.
La configuration nginx ci-dessous limitera le débit de l'API Web des analyses et comporte les éléments suivants au niveau des blocs http et emplacement (la configuration est abrégée par souci de concision) :
http {
..
limit_req_zone $binary_remote_addr zone=limit_analytics:10m rate=5r/s;
server {
..
location ~ ^/api/(\d+/)?analytics(.*)$ {
limit_req zone=limit_analytics burst=20;
proxy_pass http://localhost:8080/api/$1analytics$2$is_args$args;
..
}
}
}
Les différents éléments de la configuration peuvent être décrits comme suit :
- limit_req_zone $binary_remote_addr : la limitation du débit est effectuée par adresse IP de requête.
- zone=limit_analytics:20m : une zone de limite de débit pour l'API des analyses qui peut contenir jusqu'à 10 Mo d'adresses IP de requête.
- taux=20r/s : Chaque IP reçoit 5 requêtes par seconde.
- emplacement ~ ^/api/(\d+/)?analytics(.*)$ : les requêtes pour le point d'extrémité de l'API des analyses sont limitées en débit.
- burst=20 : des rafales contenant jusqu'à 20 requêtes seront mises en file d'attente et traitées ultérieurement ; des demandes supplémentaires conduiront à un
503.
Pour obtenir une explication complète, veuillez consulter la documentation nginx.
Rendre les ressources disponibles avec nginx¶
Dans certains cas, il est souhaitable de rendre certaines ressources accessibles au public sur le web sans exiger une quelconque authentification. C'est le cas, par exemple, lorsque vous souhaitez rendre les ressources liées à l'analyse des données de l'API Web disponibles dans un portail Web. L'exemple suivant permet d'accéder aux graphiques, aux cartes, aux rapports, aux tableaux de rapports et aux ressources documentaires par le biais d'une authentification de base en insérant un en-tête HTTP d'Autorisation dans la demande. Il supprimera l'en-tête Cookie de la requête et l'en-tête Set-Cookie de la réponse afin d'éviter de modifier l'utilisateur connecté. Il est recommandé de créer un utilisateur à cette fin, en ne lui accordant que les autorisations minimales requises. La valeur d'autorisation peut être construite en codant le nom d'utilisateur avec base64, suivi de deux points et le mot de passe et en lui ajoutant le préfixe "Basic", plus précisément "Basic base64_encode(nom d'utilisateur:mot de passe)". Il vérifiera la méthode HTTP utilisée pour les requêtes et renverra 405 Method Not Allowed s'il détecte autre chose que GET.
En utilisant cette approche, il peut être avantageux de créer un domaine séparé pour les utilisateurs publics. En effet, nous ne voulons pas modifier les informations d'identification des utilisateurs déjà connectés lorsqu'ils accèdent aux ressources publiques. Par exemple, si votre serveur est déployé à l'adresse somedomain.com, vous pouvez créer un sous-domaine dédié à api.somedomain.com et orienter les URL de votre portail vers ce sous-domaine.
http {
..
server {
listen 80;
server_name api.somedomain.com;
location ~ ^/(api/(charts|chartValues|reports|reportTables|documents|maps|organisationUnits)|dhis-web-commons/javascripts|images|dhis-web-commons-ajax-json|dhis-web-mapping|dhis-web-visualizer) {
if ($request_method != GET) {
return 405;
}
proxy_pass http://localhost:8080;
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-Proto http;
proxy_set_header Authorization "Basic YWRtaW46ZGlzdHJpY3Q=";
proxy_set_header Cookie "";
proxy_hide_header Set-Cookie;
}
}
}
Bloquer des versions spécifiques d'applications Android avec nginx¶
Dans certains cas, l'administrateur du système peut vouloir bloquer certains clients Android sur la base de leur version de l'application DHIS2 ; par exemple, si les utilisateurs sur le terrain n'ont pas mis à jour leur version de l'application Android vers une version spécifique et que l'administrateur du système veut bloquer leur accès pour forcer une mise à jour, ou à l'inverse, si l'administrateur du système veut bloquer les nouvelles versions de l'application car elles n'ont pas encore été testées. Ceci peut être facilement implémenté en utilisant des règles spécifiques User-Agent dans le fichier de configuration nginx.
http {
server {
listen 80;
server_name api.somedomain.com;
# Block the latest Android App as it has not been tested
if ( $http_user_agent ~ 'com\.dhis2/1\.2\.1/2\.2\.1/' ) {
return 403;
}
# Block Android 4.4 (API is 19) as all users should have received new tablets
if ( $http_user_agent ~ 'com\.dhis2/.*/.*/Android_19' ) {
return 403;
}
}
}
Remarque Pour l'implémentation de la méthode décrite ci-dessus, notez ce qui suit : * Avant la version 1.1.0, la chaîne User-Agent n'était pas envoyée. * De la version 1.1.0 à la version 1.3.2, le User-Agent suivait le modèle Dhis2/AppVersion/AppVersion/Android_XX. * Depuis la version 2.0.0 et plus, le User-Agent suit le modèle com.dhis2/SdkVersion/AppVersion/Android_XX * Android_XX fait référence au niveau de l'API Android, c'est-à-dire à la version d'Android telle que répertoriée [ici] (https://developer.android.com/studio/releases/platforms). * nginx utilise PCRE pour la mise en correspondance des expressions régulières.