From 44858ea18d97f4aeae50fa60119109d943292ef4 Mon Sep 17 00:00:00 2001 From: "p.delpy@dkfz-heidelberg.de" Date: Mon, 9 Sep 2024 10:01:56 +0200 Subject: [PATCH] fix: add idmanagement and obds2fhir to dhki --- dhki/modules/id-management-compose.yml | 96 +++++++++++++++++++++++++ dhki/modules/id-management-setup.sh | 53 ++++++++++++++ dhki/modules/id-management.md | 66 +++++++++++++++++ dhki/modules/obds2fhir-rest-compose.yml | 20 ++++++ dhki/modules/obds2fhir-rest-setup.sh | 13 ++++ 5 files changed, 248 insertions(+) create mode 100644 dhki/modules/id-management-compose.yml create mode 100644 dhki/modules/id-management-setup.sh create mode 100644 dhki/modules/id-management.md create mode 100644 dhki/modules/obds2fhir-rest-compose.yml create mode 100644 dhki/modules/obds2fhir-rest-setup.sh diff --git a/dhki/modules/id-management-compose.yml b/dhki/modules/id-management-compose.yml new file mode 100644 index 0000000..f9156cf --- /dev/null +++ b/dhki/modules/id-management-compose.yml @@ -0,0 +1,96 @@ +version: "3.7" + +services: + id-manager: + image: docker.verbis.dkfz.de/bridgehead/magicpl + container_name: bridgehead-id-manager + environment: + TOMCAT_REVERSEPROXY_FQDN: ${HOST} + TOMCAT_REVERSEPROXY_SSL: "true" + MAGICPL_SITE: ${IDMANAGEMENT_FRIENDLY_ID} + MAGICPL_ALLOWED_ORIGINS: https://${HOST} + MAGICPL_LOCAL_PATIENTLIST_APIKEY: ${IDMANAGER_LOCAL_PATIENTLIST_APIKEY} + MAGICPL_CENTRAXX_APIKEY: ${IDMANAGER_UPLOAD_APIKEY} + MAGICPL_CONNECTOR_APIKEY: ${IDMANAGER_READ_APIKEY} + MAGICPL_CENTRAL_PATIENTLIST_APIKEY: ${IDMANAGER_CENTRAL_PATIENTLIST_APIKEY} + MAGICPL_CONTROLNUMBERGENERATOR_APIKEY: ${IDMANAGER_CONTROLNUMBERGENERATOR_APIKEY} + depends_on: + - patientlist + - traefik-forward-auth + labels: + - "traefik.enable=true" + - "traefik.http.routers.id-manager.rule=PathPrefix(`/id-manager`)" + - "traefik.http.services.id-manager.loadbalancer.server.port=8080" + - "traefik.http.routers.id-manager.tls=true" + - "traefik.http.routers.id-manager.middlewares=traefik-forward-auth-idm" + + patientlist: + image: docker.verbis.dkfz.de/bridgehead/mainzelliste + container_name: bridgehead-patientlist + environment: + - TOMCAT_REVERSEPROXY_FQDN=${HOST} + - TOMCAT_REVERSEPROXY_SSL=true + - ML_SITE=${IDMANAGEMENT_FRIENDLY_ID} + - ML_DB_PASS=${PATIENTLIST_POSTGRES_PASSWORD} + - ML_API_KEY=${IDMANAGER_LOCAL_PATIENTLIST_APIKEY} + - ML_UPLOAD_API_KEY=${IDMANAGER_UPLOAD_APIKEY} + # Add Variables from /etc/patientlist-id-generators.env + - PATIENTLIST_SEEDS_TRANSFORMED + labels: + - "traefik.enable=true" + - "traefik.http.routers.patientlist.rule=PathPrefix(`/patientlist`)" + - "traefik.http.services.patientlist.loadbalancer.server.port=8080" + - "traefik.http.routers.patientlist.tls=true" + depends_on: + - patientlist-db + + patientlist-db: + image: docker.verbis.dkfz.de/cache/postgres:${POSTGRES_TAG} + container_name: bridgehead-patientlist-db + environment: + POSTGRES_USER: "mainzelliste" + POSTGRES_DB: "mainzelliste" + POSTGRES_PASSWORD: ${PATIENTLIST_POSTGRES_PASSWORD} + volumes: + - "patientlist-db-data:/var/lib/postgresql/data" + # NOTE: Add backups here. This is only imported if /var/lib/bridgehead/data/patientlist/ is empty!!! + - "/tmp/bridgehead/patientlist/:/docker-entrypoint-initdb.d/" + + traefik-forward-auth: + image: docker.verbis.dkfz.de/cache/oauth2-proxy/oauth2-proxy:v7.6.0 + environment: + - http_proxy=http://forward_proxy:3128 + - https_proxy=http://forward_proxy:3128 + - OAUTH2_PROXY_PROVIDER=oidc + - OAUTH2_PROXY_SKIP_PROVIDER_BUTTON=true + - OAUTH2_PROXY_OIDC_ISSUER_URL=https://login.verbis.dkfz.de/realms/master + - OAUTH2_PROXY_CLIENT_ID=bridgehead-${SITE_ID} + - OAUTH2_PROXY_CLIENT_SECRET=${IDMANAGER_AUTH_CLIENT_SECRET} + - OAUTH2_PROXY_COOKIE_SECRET=${IDMANAGER_AUTH_COOKIE_SECRET} + - OAUTH2_PROXY_COOKIE_DOMAINS=.${HOST} + - OAUTH2_PROXY_HTTP_ADDRESS=:4180 + - OAUTH2_PROXY_REVERSE_PROXY=true + - OAUTH2_PROXY_WHITELIST_DOMAINS=.${HOST} + - OAUTH2_PROXY_UPSTREAMS=static://202 + - OAUTH2_PROXY_EMAIL_DOMAINS=* + - OAUTH2_PROXY_SCOPE=openid profile email + # Pass Authorization Header and some user information to backend services + - OAUTH2_PROXY_SET_AUTHORIZATION_HEADER=true + - OAUTH2_PROXY_SET_XAUTHREQUEST=true + # Keycloak has an expiration time of 60s therefore oauth2-proxy needs to refresh after that + - OAUTH2_PROXY_COOKIE_REFRESH=60s + - OAUTH2_PROXY_ALLOWED_GROUPS=DKTK-CCP-PPSN + - OAUTH2_PROXY_PROXY_PREFIX=/oauth2-idm + labels: + - "traefik.enable=true" + - "traefik.http.services.traefik-forward-auth.loadbalancer.server.port=4180" + - "traefik.http.routers.traefik-forward-auth.rule=Host(`${HOST}`) && PathPrefix(`/oauth2-idm`)" + - "traefik.http.routers.traefik-forward-auth.tls=true" + - "traefik.http.middlewares.traefik-forward-auth-idm.forwardauth.address=http://traefik-forward-auth:4180" + - "traefik.http.middlewares.traefik-forward-auth-idm.forwardauth.authResponseHeaders=Authorization" + depends_on: + forward_proxy: + condition: service_healthy + +volumes: + patientlist-db-data: diff --git a/dhki/modules/id-management-setup.sh b/dhki/modules/id-management-setup.sh new file mode 100644 index 0000000..3165956 --- /dev/null +++ b/dhki/modules/id-management-setup.sh @@ -0,0 +1,53 @@ +#!/bin/bash -e + +function idManagementSetup() { + if [ -n "$IDMANAGER_UPLOAD_APIKEY" ]; then + log INFO "id-management setup detected -- will start id-management (mainzelliste & magicpl)." + OVERRIDE+=" -f ./$PROJECT/modules/id-management-compose.yml" + + # Auto Generate local Passwords + PATIENTLIST_POSTGRES_PASSWORD="$(echo \"id-management-module-db-password-salt\" | openssl pkeyutl -sign -inkey /etc/bridgehead/pki/${SITE_ID}.priv.pem | base64 | head -c 30)" + IDMANAGER_LOCAL_PATIENTLIST_APIKEY="$(cat /proc/sys/kernel/random/uuid | sed 's/[-]//g' | head -c 20)" + + # Transform Seeds Configuration to pass it to the Mainzelliste Container + PATIENTLIST_SEEDS_TRANSFORMED="$(declare -p PATIENTLIST_SEEDS | tr -d '\"' | sed 's/\[/\[\"/g' | sed 's/\]/\"\]/g')" + + # Ensure old ids are working !!! + export IDMANAGEMENT_FRIENDLY_ID=$(legacyIdMapping "$SITE_ID") + fi +} + +# Transform into single string array, e.g. 'dktk-test' to 'dktk test' +# Usage: transformToSingleStringArray 'dktk-test' -> 'dktk test' +function transformToSingleStringArray() { + echo "${1//-/ }"; +} + +# Ensure all Words are Uppercase +# Usage: transformToUppercase 'dktk test' -> 'Dktk Test' +function transformToUppercase() { + result=""; + for word in $1; do + result+=" ${word^}"; + done + echo "$result"; +} + +# Handle all execeptions from the norm (e.g LMU, TUM) +# Usage: applySpecialCases 'Muenchen Lmu Test' -> 'Muenchen LMU Test' +function applySpecialCases() { + result="$1"; + result="${result/Lmu/LMU}"; + result="${result/Tum/TUM}"; + result="${result/Dktk Test/Teststandort}"; + echo "$result"; +} + +# Transform current siteids to legacy version +# Usage: legacyIdMapping "dktk-test" -> "DktkTest" +function legacyIdMapping() { + single_string_array=$(transformToSingleStringArray "$1"); + uppercase_string=$(transformToUppercase "$single_string_array"); + normalized_string=$(applySpecialCases "$uppercase_string"); + echo "$normalized_string" | tr -d ' ' +} diff --git a/dhki/modules/id-management.md b/dhki/modules/id-management.md new file mode 100644 index 0000000..66f9f71 --- /dev/null +++ b/dhki/modules/id-management.md @@ -0,0 +1,66 @@ +# Module: Id-Management +This module provides integration with the CCP-Pseudonymiziation Service. To learn more on the backgrounds of this service, you can refer to the [CCP Data Protection Concept](https://dktk.dkfz.de/klinische-plattformen/documents-download). + +## Getting Started +The following configuration variables are added to your sites-configuration repository: + +``` +IDMANAGER_UPLOAD_APIKEY="" +IDMANAGER_READ_APIKEY="" +IDMANAGER_CENTRAL_PATIENTLIST_APIKEY="" +IDMANAGER_CONTROLNUMBERGENERATOR_APIKEY="" +IDMANAGER_AUTH_CLIENT_ID="" +IDMANAGER_AUTH_CLIENT_SECRET="" + +IDMANAGER_SEEDS_BK="" +IDMANAGER_SEEDS_MDS="" +IDMANAGER_SEEDS_DKTK000001985="" +``` +> NOTE: Additionally, the CCP-IT adds lines declaring the `PATIENTLIST_SEEDS` array in your site configuration. This will contain the seeds for the different id-generators used in all projects. + +Once your Bridgehead is updated and restarted, you're all set! + +## Additional information you may want to know + +### Services + +Upon configuration, the Bridgehead will spawn the following services: + +- The `bridgehead-id-manager` at https://bridgehead.local/id-manager, provides a common interface for creating pseudonyms in the bridgehead. +- The `bridgehead-patientlist` at https://bridgehead.local/patientlist is a local instance of the open-source software [Mainzelliste](https://mainzelliste.de). This service's primary task is to map patients IDAT to pseudonyms identifying them along the different CCP projects. +- The `bridgehead-patientlist-db` is only accessible within the Bridgehead itself. This is a local postgresql instance storing the database for `bridgehead-patientlist`. The data is persisted as a named volume `patientlist-db-data`. + +### How to import an existing database (e.g from Legacy Windows or from Backups) +First you must shutdown your local bridgehead instance: +``` +systemctl stop bridgehead@ccp +``` + +Next you need to remove the current patientlist database: +``` +docker volume rm patientlist-db-data; +``` + +Third, you need to place your postgres dump in the import directory `/tmp/bridgehead/patientlist/some-dump.sql`. This will only be imported, then the volume `patientlist-db-data` was removed previously. +> NOTE: Please create the postgres dump with the options "--no-owner" and "--no-privileges". Additionally ensure the dump is created in the plain format (SQL). + +After this, you can restart your bridgehead and the dump will be imported: +``` +systemctl start bridgehead@ccp +``` + +### How to connect your local data-management +Typically, the sites connect their local data-management for the pseudonym creation with the id-management in the bridgehead. In the following two sections, you can read where you can change the configuration: +#### Sites using CentraXX +On your CentraXX Server, you need to change following settings in the "centraxx-dev.properties" file. +``` +dktk.idmanagement.url=https:///id-manager/translator/getId +dktk.idmanagement.apiKey= +``` +They typically already exist, but need to be changed to the new values! +#### Sites using ADT2FHIR +@Pierre + + +### How to connect the legacy windows bridgehead +You need to change the configuration file "..." of your Windows Bridgehead. TODO... diff --git a/dhki/modules/obds2fhir-rest-compose.yml b/dhki/modules/obds2fhir-rest-compose.yml new file mode 100644 index 0000000..f201e23 --- /dev/null +++ b/dhki/modules/obds2fhir-rest-compose.yml @@ -0,0 +1,20 @@ +version: "3.7" + +services: + obds2fhir-rest: + container_name: bridgehead-obds2fhir-rest + image: docker.verbis.dkfz.de/ccp/obds2fhir-rest:main + environment: + IDTYPE: BK_${IDMANAGEMENT_FRIENDLY_ID}_L-ID + MAINZELLISTE_APIKEY: ${IDMANAGER_LOCAL_PATIENTLIST_APIKEY} + SALT: ${LOCAL_SALT} + KEEP_INTERNAL_ID: ${KEEP_INTERNAL_ID:-false} + MAINZELLISTE_URL: ${PATIENTLIST_URL:-http://patientlist:8080/patientlist} + restart: always + labels: + - "traefik.enable=true" + - "traefik.http.routers.obds2fhir-rest.rule=PathPrefix(`/obds2fhir-rest`) || PathPrefix(`/adt2fhir-rest`)" + - "traefik.http.middlewares.obds2fhir-rest_strip.stripprefix.prefixes=/obds2fhir-rest,/adt2fhir-rest" + - "traefik.http.services.obds2fhir-rest.loadbalancer.server.port=8080" + - "traefik.http.routers.obds2fhir-rest.tls=true" + - "traefik.http.routers.obds2fhir-rest.middlewares=obds2fhir-rest_strip,auth" diff --git a/dhki/modules/obds2fhir-rest-setup.sh b/dhki/modules/obds2fhir-rest-setup.sh new file mode 100644 index 0000000..677ea63 --- /dev/null +++ b/dhki/modules/obds2fhir-rest-setup.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +function obds2fhirRestSetup() { + if [ -n "$ENABLE_OBDS2FHIR_REST" ]; then + log INFO "oBDS2FHIR-REST setup detected -- will start obds2fhir-rest module." + if [ ! -n "$IDMANAGER_UPLOAD_APIKEY" ]; then + log ERROR "Missing ID-Management Module! Fix this by setting up ID Management:" + PATIENTLIST_URL=" " + fi + OVERRIDE+=" -f ./$PROJECT/modules/obds2fhir-rest-compose.yml" + LOCAL_SALT="$(echo \"local-random-salt\" | openssl pkeyutl -sign -inkey /etc/bridgehead/pki/${SITE_ID}.priv.pem | base64 | head -c 30)" + fi +}