Merge pull request #145 from samply/feature/datashield-central-keycloak

Remove local Keycloak Installation
This commit is contained in:
djuarezgf 2024-03-13 10:34:13 +01:00 committed by GitHub
commit f88dfb5654
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 304 additions and 174 deletions

View File

@ -41,6 +41,7 @@ case "$PROJECT" in
;; ;;
esac esac
# TODO: Please add proper documentation for variable priorities (1. secrets, 2. vars, 3. PROJECT.local.conf, 4. PROJECT.conf, 5. ???
loadVars() { loadVars() {
# Load variables from /etc/bridgehead and /srv/docker/bridgehead # Load variables from /etc/bridgehead and /srv/docker/bridgehead
set -a set -a
@ -50,6 +51,7 @@ loadVars() {
source /etc/bridgehead/$PROJECT.local.conf || fail_and_report 1 "Found /etc/bridgehead/$PROJECT.local.conf but failed to import" source /etc/bridgehead/$PROJECT.local.conf || fail_and_report 1 "Found /etc/bridgehead/$PROJECT.local.conf but failed to import"
fi fi
fetchVarsFromVaultByFile /etc/bridgehead/$PROJECT.conf || fail_and_report 1 "Unable to fetchVarsFromVaultByFile" fetchVarsFromVaultByFile /etc/bridgehead/$PROJECT.conf || fail_and_report 1 "Unable to fetchVarsFromVaultByFile"
setHostname
[ -e ./$PROJECT/vars ] && source ./$PROJECT/vars [ -e ./$PROJECT/vars ] && source ./$PROJECT/vars
set +a set +a
@ -64,7 +66,6 @@ loadVars() {
OVERRIDE+=" -f ./$PROJECT/docker-compose.override.yml" OVERRIDE+=" -f ./$PROJECT/docker-compose.override.yml"
fi fi
detectCompose detectCompose
setHostname
setupProxy setupProxy
# Set some project-independent default values # Set some project-independent default values
@ -89,6 +90,7 @@ case "$ACTION" in
loadVars loadVars
hc_send log "Bridgehead $PROJECT startup: Checking requirements ..." hc_send log "Bridgehead $PROJECT startup: Checking requirements ..."
checkRequirements checkRequirements
sync_secrets
hc_send log "Bridgehead $PROJECT startup: Requirements checked out. Now starting bridgehead ..." hc_send log "Bridgehead $PROJECT startup: Requirements checked out. Now starting bridgehead ..."
exec $COMPOSE -p $PROJECT -f ./minimal/docker-compose.yml -f ./$PROJECT/docker-compose.yml $OVERRIDE up --abort-on-container-exit exec $COMPOSE -p $PROJECT -f ./minimal/docker-compose.yml -f ./$PROJECT/docker-compose.yml $OVERRIDE up --abort-on-container-exit
;; ;;

View File

@ -19,7 +19,7 @@ services:
- "traefik.http.routers.blaze_ccp.tls=true" - "traefik.http.routers.blaze_ccp.tls=true"
focus: focus:
image: docker.verbis.dkfz.de/cache/samply/focus:${FOCUS_TAG} image: docker.verbis.dkfz.de/cache/samply/focus:0.4.0
container_name: bridgehead-focus container_name: bridgehead-focus
environment: environment:
API_KEY: ${FOCUS_BEAM_SECRET_SHORT} API_KEY: ${FOCUS_BEAM_SECRET_SHORT}

View File

@ -6,15 +6,20 @@ services:
image: docker.verbis.dkfz.de/ccp/dktk-rstudio:latest image: docker.verbis.dkfz.de/ccp/dktk-rstudio:latest
environment: environment:
#DEFAULT_USER: "rstudio" # This line is kept for informational purposes #DEFAULT_USER: "rstudio" # This line is kept for informational purposes
PASSWORD: "${LDM_AUTH}" PASSWORD: "${RSTUDIO_ADMIN_PASSWORD}" # It is required, even if the authentication is disabled
DISABLE_AUTH: "true" # https://rocker-project.org/images/versioned/rstudio.html#how-to-use
# TODO: Connect R-Studio with central Keycloak. Currently using Traefik authentication.
HTTP_RELATIVE_PATH: "/rstudio" HTTP_RELATIVE_PATH: "/rstudio"
ALL_PROXY: "http://forward_proxy:3128" # https://rocker-project.org/use/networking.html
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.rstudio_ccp.rule=PathPrefix(`/rstudio`)" - "traefik.http.routers.rstudio_ccp.rule=PathPrefix(`/rstudio`)"
- "traefik.http.services.rstudio_ccp.loadbalancer.server.port=8787" - "traefik.http.services.rstudio_ccp.loadbalancer.server.port=8787"
- "traefik.http.routers.rstudio_ccp.tls=true"
- "traefik.http.middlewares.rstudio_ccp_strip.stripprefix.prefixes=/rstudio" - "traefik.http.middlewares.rstudio_ccp_strip.stripprefix.prefixes=/rstudio"
- "traefik.http.routers.rstudio_ccp.middlewares=rstudio_ccp_strip" - "traefik.http.routers.rstudio_ccp.tls=true"
- "traefik.http.routers.rstudio_ccp.middlewares=oidcAuth,rstudio_ccp_strip"
networks:
- rstudio
opal: opal:
container_name: bridgehead-opal container_name: bridgehead-opal
@ -30,7 +35,7 @@ services:
environment: environment:
JAVA_OPTS: "-Xms1G -Xmx8G -XX:+UseG1GC -Dhttps.proxyHost=forward_proxy -Dhttps.proxyPort=3128" JAVA_OPTS: "-Xms1G -Xmx8G -XX:+UseG1GC -Dhttps.proxyHost=forward_proxy -Dhttps.proxyPort=3128"
# OPAL_ADMINISTRATOR_USER: "administrator" # This line is kept for informational purposes # OPAL_ADMINISTRATOR_USER: "administrator" # This line is kept for informational purposes
OPAL_ADMINISTRATOR_PASSWORD: "${LDM_AUTH}" OPAL_ADMINISTRATOR_PASSWORD: "${OPAL_ADMIN_PASSWORD}"
POSTGRESDATA_HOST: "opal-db" POSTGRESDATA_HOST: "opal-db"
POSTGRESDATA_DATABASE: "opal" POSTGRESDATA_DATABASE: "opal"
POSTGRESDATA_USER: "opal" POSTGRESDATA_USER: "opal"
@ -40,11 +45,21 @@ services:
APP_CONTEXT_PATH: "/opal" APP_CONTEXT_PATH: "/opal"
OPAL_PRIVATE_KEY: "/run/secrets/opal-key.pem" OPAL_PRIVATE_KEY: "/run/secrets/opal-key.pem"
OPAL_CERTIFICATE: "/run/secrets/opal-cert.pem" OPAL_CERTIFICATE: "/run/secrets/opal-cert.pem"
OIDC_URL: "${OIDC_URL}"
OIDC_REALM: "${OIDC_REALM}"
OIDC_CLIENT_ID: "${OIDC_PRIVATE_CLIENT_ID}"
OIDC_CLIENT_SECRET: "${OIDC_CLIENT_SECRET}"
OIDC_ADMIN_GROUP: "${OIDC_ADMIN_GROUP}"
TOKEN_MANAGER_PASSWORD: "${TOKEN_MANAGER_OPAL_PASSWORD}"
EXPORTER_PASSWORD: "${EXPORTER_OPAL_PASSWORD}"
BEAM_APP_ID: token-manager.${PROXY_ID}
BEAM_SECRET: ${TOKEN_MANAGER_SECRET}
BEAM_DATASHIELD_PROXY: request-manager
volumes:
- "/var/cache/bridgehead/ccp/opal-metadata-db:/srv" # Opal metadata
secrets: secrets:
- opal-cert.pem - opal-cert.pem
- opal-key.pem - opal-key.pem
tmpfs:
- /srv
opal-db: opal-db:
container_name: bridgehead-opal-db container_name: bridgehead-opal-db
@ -54,11 +69,11 @@ services:
POSTGRES_USER: "opal" POSTGRES_USER: "opal"
POSTGRES_DB: "opal" POSTGRES_DB: "opal"
volumes: volumes:
- "/var/cache/bridgehead/ccp/opal-db:/var/lib/postgresql/data" - "/var/cache/bridgehead/ccp/opal-db:/var/lib/postgresql/data" # Opal project data (imported from exporter)
opal-rserver: opal-rserver:
container_name: bridgehead-opal-rserver container_name: bridgehead-opal-rserver
image: docker.verbis.dkfz.de/cache/datashield/rock-base:6.3 # https://datashield.discourse.group/t/ds-aggregate-method-error/416/4 image: docker.verbis.dkfz.de/ccp/dktk-rserver # datashield/rock-base + dsCCPhos
tmpfs: tmpfs:
- /srv - /srv
@ -79,13 +94,80 @@ services:
- beam-proxy - beam-proxy
volumes: volumes:
- /tmp/bridgehead/opal-map/:/map/:ro - /tmp/bridgehead/opal-map/:/map/:ro
networks:
- default
- rstudio
traefik:
labels:
- "traefik.http.middlewares.oidcAuth.forwardAuth.address=http://oauth2_proxy:4180/"
- "traefik.http.middlewares.oidcAuth.forwardAuth.trustForwardHeader=true"
- "traefik.http.middlewares.oidcAuth.forwardAuth.authResponseHeaders=X-Auth-Request-Access-Token,Authorization"
networks:
- default
- rstudio
forward_proxy:
networks:
- default
- rstudio
beam-proxy: beam-proxy:
environment: environment:
APP_datashield-connect_KEY: ${DATASHIELD_CONNECT_SECRET} APP_datashield-connect_KEY: ${DATASHIELD_CONNECT_SECRET}
APP_token-manager_KEY: ${TOKEN_MANAGER_SECRET}
# TODO: Allow users of group /DataSHIELD and OIDC_USER_GROUP at the same time:
# Maybe a solution would be (https://oauth2-proxy.github.io/oauth2-proxy/configuration/oauth_provider):
# --allowed-groups=/DataSHIELD,OIDC_USER_GROUP
oauth2_proxy:
image: docker.verbis.dkfz.de/cache/oauth2-proxy/oauth2-proxy:latest
container_name: bridgehead_oauth2_proxy
command: >-
--allowed-group=DataSHIELD
--oidc-groups-claim=${OIDC_GROUP_CLAIM}
--auth-logging=true
--whitelist-domain=${HOST}
--http-address="0.0.0.0:4180"
--reverse-proxy=true
--upstream="static://202"
--email-domain="*"
--cookie-name="_BRIDGEHEAD_oauth2"
--cookie-secret="${OAUTH2_PROXY_SECRET}"
--cookie-expire="12h"
--cookie-secure="true"
--cookie-httponly="true"
#OIDC settings
--provider="keycloak-oidc"
--provider-display-name="VerbIS Login"
--client-id="${OIDC_PRIVATE_CLIENT_ID}"
--client-secret="${OIDC_CLIENT_SECRET}"
--redirect-url="https://${HOST}${OAUTH2_CALLBACK}"
--oidc-issuer-url="${OIDC_ISSUER_URL}"
--scope="openid email profile"
--code-challenge-method="S256"
--skip-provider-button=true
#X-Forwarded-Header settings - true/false depending on your needs
--pass-basic-auth=true
--pass-user-headers=false
--pass-access-token=false
labels:
- "traefik.enable=true"
- "traefik.http.routers.oauth2_proxy.rule=Host(`${HOST}`) && PathPrefix(`/oauth2`, `/oauth2/callback`)"
- "traefik.http.services.oauth2_proxy.loadbalancer.server.port=4180"
- "traefik.http.routers.oauth2_proxy.tls=true"
environment:
http_proxy: "http://forward_proxy:3128"
https_proxy: "http://forward_proxy:3128"
depends_on:
forward_proxy:
condition: service_healthy
secrets: secrets:
opal-cert.pem: opal-cert.pem:
file: /tmp/bridgehead/opal-cert.pem file: /tmp/bridgehead/opal-cert.pem
opal-key.pem: opal-key.pem:
file: /tmp/bridgehead/opal-key.pem file: /tmp/bridgehead/opal-key.pem
networks:
rstudio:

View File

@ -1,59 +0,0 @@
{
"sites": [
{
"id": "berlin",
"name": "berlin",
"virtualhost": "opal-berlin",
"beamconnect": "datashield-connect.berlin.broker.ccp-it.dktk.dkfz.de"
},
{
"id": "muenchen-lmu",
"name": "muenchen-lmu",
"virtualhost": "opal-muenchen-lmu",
"beamconnect": "datashield-connect.muenchen-lmu.broker.ccp-it.dktk.dkfz.de"
},
{
"id": "dresden",
"name": "dresden",
"virtualhost": "opal-dresden",
"beamconnect": "datashield-connect.dresden.broker.ccp-it.dktk.dkfz.de"
},
{
"id": "freiburg",
"name": "freiburg",
"virtualhost": "opal-freiburg",
"beamconnect": "datashield-connect.freiburg.broker.ccp-it.dktk.dkfz.de"
},
{
"id": "muenchen-tum",
"name": "muenchen-tum",
"virtualhost": "opal-muenchen-tum",
"beamconnect": "datashield-connect.muenchen-tum.broker.ccp-it.dktk.dkfz.de"
},
{
"id": "tuebingen",
"name": "tuebingen",
"virtualhost": "opal-tuebingen",
"beamconnect": "datashield-connect.tuebingen.broker.ccp-it.dktk.dkfz.de"
},
{
"id": "mainz",
"name": "mainz",
"virtualhost": "opal-mainz",
"beamconnect": "datashield-connect.mainz.broker.ccp-it.dktk.dkfz.de"
},
{
"id": "frankfurt",
"name": "frankfurt",
"virtualhost": "opal-frankfurt",
"beamconnect": "datashield-connect.frankfurt.broker.ccp-it.dktk.dkfz.de"
},
{
"id": "essen",
"name": "essen",
"virtualhost": "opal-essen",
"beamconnect": "datashield-connect.essen.broker.ccp-it.dktk.dkfz.de"
}
]
}

View File

@ -1,23 +1,39 @@
#!/bin/bash -e #!/bin/bash -e
if [ "$ENABLE_DATASHIELD" == true ]; then if [ "$ENABLE_DATASHIELD" == true ]; then
# HACK: This only works because exporter-setup.sh and teiler-setup.sh are sourced after datashield-setup.sh
ENABLE_EXPORTER=true
ENABLE_TEILER=true
log INFO "DataSHIELD setup detected -- will start DataSHIELD services." log INFO "DataSHIELD setup detected -- will start DataSHIELD services."
OVERRIDE+=" -f ./$PROJECT/modules/datashield-compose.yml" OVERRIDE+=" -f ./$PROJECT/modules/datashield-compose.yml"
OPAL_DB_PASSWORD="$(echo \"This is a salt string to generate one consistent password for Opal. It is not required to be secret.\" | openssl rsautl -sign -inkey /etc/bridgehead/pki/${SITE_ID}.priv.pem | base64 | head -c 30)" EXPORTER_OPAL_PASSWORD="$(generate_password \"exporter in Opal\")"
DATASHIELD_CONNECT_SECRET="$(echo \"This is a salt string to generate one consistent password as the DataShield Connect secret. It is not required to be secret.\" | openssl rsautl -sign -inkey /etc/bridgehead/pki/${SITE_ID}.priv.pem | base64 | head -c 30)" TOKEN_MANAGER_OPAL_PASSWORD="$(generate_password \"Token Manager in Opal\")"
OPAL_DB_PASSWORD="$(echo \"Opal DB\" | generate_simple_password)"
OPAL_ADMIN_PASSWORD="$(generate_password \"admin password for Opal\")"
RSTUDIO_ADMIN_PASSWORD="$(generate_password \"admin password for R-Studio\")"
DATASHIELD_CONNECT_SECRET="$(echo \"DataShield Connect\" | generate_simple_password)"
TOKEN_MANAGER_SECRET="$(echo \"Token Manager\" | generate_simple_password)"
if [ ! -e /tmp/bridgehead/opal-cert.pem ]; then if [ ! -e /tmp/bridgehead/opal-cert.pem ]; then
mkdir -p /tmp/bridgehead/ mkdir -p /tmp/bridgehead/
chown -R bridgehead:docker /tmp/bridgehead/ openssl req -x509 -newkey rsa:4096 -nodes -keyout /tmp/bridgehead/opal-key.pem -out /tmp/bridgehead/opal-cert.pem -days 3650 -subj "/CN=opal/C=DE"
openssl req -x509 -newkey rsa:4096 -nodes -keyout /tmp/bridgehead/opal-key.pem -out /tmp/bridgehead/opal-cert.pem -days 3650 -subj "/CN=${HOST:-opal}/C=DE"
chmod g+r /tmp/bridgehead/opal-key.pem
fi fi
mkdir -p /tmp/bridgehead/opal-map mkdir -p /tmp/bridgehead/opal-map
jq -n --argfile input ./$PROJECT/modules/datashield-mappings.json ' sites="$(cat ./$PROJECT/modules/datashield-sites.json)"
[{ echo "$sites" | docker_jq -n --args '{"sites": input | map({
"external": "opal-'"$SITE_ID"'", "name": .,
"internal": "opal:8080", "id": .,
"allowed": [$input.sites[].id | "datashield-connect.\(.).broker.ccp-it.dktk.dkfz.de"] "virtualhost": "\(.):443",
}]' > /tmp/bridgehead/opal-map/local.json "beamconnect": "datashield-connect.\(.).'"$BROKER_ID"'"
cp -f ./$PROJECT/modules/datashield-mappings.json /tmp/bridgehead/opal-map/central.json })}' $sites > /tmp/bridgehead/opal-map/central.json
chown -R bridgehead:docker /tmp/bridgehead/ echo "$sites" | docker_jq -n --args '[{
"external": "'"$SITE_ID"':443",
"internal": "opal:8443",
"allowed": input | map("datashield-connect.\(.).'"$BROKER_ID"'")
}]' > /tmp/bridgehead/opal-map/local.json
if [ "$USER" == "root" ]; then
chown -R bridgehead:docker /tmp/bridgehead
chmod g+wr /tmp/bridgehead/opal-map/*
chmod g+r /tmp/bridgehead/opal-key.pem
fi
add_private_oidc_redirect_url "/opal/*"
fi fi

View File

@ -0,0 +1,14 @@
[
"berlin",
"muenchen-lmu",
"dresden",
"freiburg",
"muenchen-tum",
"tuebingen",
"mainz",
"frankfurt",
"essen",
"dktk-datashield-test",
"dktk-test",
"mannheim"
]

View File

@ -15,7 +15,7 @@ services:
HTTP_RELATIVE_PATH: "/ccp-exporter" HTTP_RELATIVE_PATH: "/ccp-exporter"
SITE: "${SITE_ID}" SITE: "${SITE_ID}"
HTTP_SERVLET_REQUEST_SCHEME: "https" HTTP_SERVLET_REQUEST_SCHEME: "https"
OPAL_ADMINISTRATOR_PASSWORD: "${LDM_AUTH}" OPAL_PASSWORD: "${EXPORTER_OPAL_PASSWORD}"
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.exporter_ccp.rule=PathPrefix(`/ccp-exporter`)" - "traefik.http.routers.exporter_ccp.rule=PathPrefix(`/ccp-exporter`)"

View File

@ -1,47 +0,0 @@
version: "3.7"
services:
login-db:
image: docker.verbis.dkfz.de/cache/postgres:${POSTGRES_TAG}
container_name: bridgehead-login-db
environment:
POSTGRES_USER: "keycloak"
POSTGRES_PASSWORD: "${KEYCLOAK_DB_PASSWORD}" # Set in login-setup.sh
POSTGRES_DB: "keycloak"
tmpfs:
- /var/lib/postgresql/data
# Consider removing this comment once we have collected experience in production.
# volumes:
# - "bridgehead-login-db:/var/lib/postgresql/data"
login:
image: docker.verbis.dkfz.de/ccp/dktk-keycloak:latest
container_name: bridgehead-login
environment:
KEYCLOAK_ADMIN: "admin"
KEYCLOAK_ADMIN_PASSWORD: "${LDM_AUTH}"
TEILER_ADMIN: "${PROJECT}"
TEILER_ADMIN_PASSWORD: "${LDM_AUTH}"
TEILER_ADMIN_FIRST_NAME: "${OPERATOR_FIRST_NAME}"
TEILER_ADMIN_LAST_NAME: "${OPERATOR_LAST_NAME}"
TEILER_ADMIN_EMAIL: "${OPERATOR_EMAIL}"
KC_DB_PASSWORD: "${KEYCLOAK_DB_PASSWORD}" # Set in login-setup.sh
KC_HOSTNAME_URL: "https://${HOST}/login"
KC_HOSTNAME_STRICT: "false"
KC_PROXY_ADDRESS_FORWARDING: "true"
TEILER_ORCHESTRATOR_EXTERN_URL: "https://${HOST}/ccp-teiler"
command:
- start-dev --import-realm --proxy edge --http-relative-path=/login
labels:
- "traefik.enable=true"
- "traefik.http.routers.login.rule=PathPrefix(`/login`)"
- "traefik.http.services.login.loadbalancer.server.port=8080"
- "traefik.http.routers.login.tls=true"
depends_on:
- login-db
# Consider removing this comment once we have collected experience in production.
#volumes:
# bridgehead-login-db:
# name: "bridgehead-login-db"

View File

@ -1,7 +0,0 @@
#!/bin/bash -e
if [ "$ENABLE_LOGIN" == true ]; then
log INFO "Login setup detected -- will start Login services."
OVERRIDE+=" -f ./$PROJECT/modules/login-compose.yml"
KEYCLOAK_DB_PASSWORD="$(echo \"This is a salt string to generate one consistent password for Keycloak. It is not required to be secret.\" | openssl rsautl -sign -inkey /etc/bridgehead/pki/${SITE_ID}.priv.pem | base64 | head -c 30)"
fi

View File

@ -1,13 +0,0 @@
# Login
The login component is a local Keycloak instance. In the future will be replaced by the central keycloak instance
or maybe can be used to add local identity providers to the bridgehead or just to simplify the configuration of
the central keycloak instance for the integration of every new bridgehead.
The basic configuration of our Keycloak instance is contained in a small json file.
### Teiler User
Currently, the local keycloak is used by the teiler. There is a basic admin user in the basic configuration of keycloak.
The user can be configured with the environment variables TEILER_ADMIN_XXX.
## Login-DB
Keycloak requires a local database for its configuration. However, as we use an initial json configuration file, if no
local identity provider is configured nor any local user, theoretically we don't need a volume for the login.

View File

@ -2,7 +2,7 @@ version: "3.7"
services: services:
mtba: mtba:
image: docker.verbis.dkfz.de/cache/samply/mtba:1.0.0 image: docker.verbis.dkfz.de/cache/samply/mtba:develop
container_name: bridgehead-mtba container_name: bridgehead-mtba
environment: environment:
BLAZE_STORE_URL: http://blaze:8080 BLAZE_STORE_URL: http://blaze:8080
@ -11,21 +11,27 @@ services:
ID_MANAGER_API_KEY: ${IDMANAGER_UPLOAD_APIKEY} ID_MANAGER_API_KEY: ${IDMANAGER_UPLOAD_APIKEY}
ID_MANAGER_PSEUDONYM_ID_TYPE: BK_${IDMANAGEMENT_FRIENDLY_ID}_L-ID ID_MANAGER_PSEUDONYM_ID_TYPE: BK_${IDMANAGEMENT_FRIENDLY_ID}_L-ID
ID_MANAGER_URL: http://id-manager:8080/id-manager ID_MANAGER_URL: http://id-manager:8080/id-manager
PATIENT_CSV_FIRST_NAME_HEADER: ${MTBA_PATIENT_CSV_FIRST_NAME_HEADER} PATIENT_CSV_FIRST_NAME_HEADER: ${MTBA_PATIENT_CSV_FIRST_NAME_HEADER:-FIRST_NAME}
PATIENT_CSV_LAST_NAME_HEADER: ${MTBA_PATIENT_CSV_LAST_NAME_HEADER} PATIENT_CSV_LAST_NAME_HEADER: ${MTBA_PATIENT_CSV_LAST_NAME_HEADER:-LAST_NAME}
PATIENT_CSV_GENDER_HEADER: ${MTBA_PATIENT_CSV_GENDER_HEADER} PATIENT_CSV_GENDER_HEADER: ${MTBA_PATIENT_CSV_GENDER_HEADER:-GENDER}
PATIENT_CSV_BIRTHDAY_HEADER: ${MTBA_PATIENT_CSV_BIRTHDAY_HEADER} PATIENT_CSV_BIRTHDAY_HEADER: ${MTBA_PATIENT_CSV_BIRTHDAY_HEADER:-BIRTHDAY}
CBIOPORTAL_URL: http://cbioportal:8080 CBIOPORTAL_URL: http://cbioportal:8080
FILE_CHARSET: ${MTBA_FILE_CHARSET} FILE_CHARSET: ${MTBA_FILE_CHARSET:-UTF-8}
FILE_END_OF_LINE: ${MTBA_FILE_END_OF_LINE} FILE_END_OF_LINE: ${MTBA_FILE_END_OF_LINE:-LF}
CSV_DELIMITER: ${MTBA_CSV_DELIMITER} CSV_DELIMITER: ${MTBA_CSV_DELIMITER:-TAB}
HTTP_RELATIVE_PATH: "/mtba"
OIDC_ADMIN_GROUP: "${OIDC_ADMIN_GROUP}"
OIDC_CLIENT_ID: "${OIDC_PRIVATE_CLIENT_ID}"
OIDC_CLIENT_SECRET: "${OIDC_CLIENT_SECRET}"
OIDC_REALM: "${OIDC_REALM}"
OIDC_URL: "${OIDC_URL}"
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.mtba_ccp.rule=PathPrefix(`/mtba`)" - "traefik.http.routers.mtba_ccp.rule=PathPrefix(`/mtba`)"
- "traefik.http.services.mtba_ccp.loadbalancer.server.port=8480" - "traefik.http.services.mtba_ccp.loadbalancer.server.port=8480"
- "traefik.http.routers.mtba_ccp.tls=true" - "traefik.http.routers.mtba_ccp.tls=true"
- "traefik.http.middlewares.mtba_ccp_strip.stripprefix.prefixes=/mtba"
- "traefik.http.routers.mtba_ccp.middlewares=mtba_ccp_strip, auth"
volumes: volumes:
- /var/cache/bridgehead/ccp/mtba/input:/app/input - /var/cache/bridgehead/ccp/mtba/input:/app/input
- /var/cache/bridgehead/ccp/mtba/persist:/app/persist - /var/cache/bridgehead/ccp/mtba/persist:/app/persist

View File

@ -8,5 +8,6 @@ function mtbaSetup() {
exit 1; exit 1;
fi fi
OVERRIDE+=" -f ./$PROJECT/modules/mtba-compose.yml" OVERRIDE+=" -f ./$PROJECT/modules/mtba-compose.yml"
add_private_oidc_redirect_url "/mtba/*"
fi fi
} }

View File

@ -3,7 +3,7 @@ version: "3.7"
services: services:
teiler-orchestrator: teiler-orchestrator:
image: docker.verbis.dkfz.de/cache/samply/teiler-orchestrator:develop image: docker.verbis.dkfz.de/cache/samply/teiler-orchestrator:latest
container_name: bridgehead-teiler-orchestrator container_name: bridgehead-teiler-orchestrator
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
@ -31,9 +31,10 @@ services:
environment: environment:
DEFAULT_LANGUAGE: "${DEFAULT_LANGUAGE}" DEFAULT_LANGUAGE: "${DEFAULT_LANGUAGE}"
TEILER_BACKEND_URL: "https://${HOST}/ccp-teiler-backend" TEILER_BACKEND_URL: "https://${HOST}/ccp-teiler-backend"
KEYCLOAK_URL: "https://${HOST}/login" OIDC_URL: "${OIDC_URL}"
KEYCLOAK_REALM: "teiler" OIDC_REALM: "${OIDC_REALM}"
KEYCLOAK_CLIENT_ID: "teiler" OIDC_CLIENT_ID: "${OIDC_PUBLIC_CLIENT_ID}"
OIDC_TOKEN_GROUP: "${OIDC_GROUP_CLAIM}"
TEILER_ADMIN_NAME: "${OPERATOR_FIRST_NAME} ${OPERATOR_LAST_NAME}" TEILER_ADMIN_NAME: "${OPERATOR_FIRST_NAME} ${OPERATOR_LAST_NAME}"
TEILER_ADMIN_EMAIL: "${OPERATOR_EMAIL}" TEILER_ADMIN_EMAIL: "${OPERATOR_EMAIL}"
TEILER_ADMIN_PHONE: "${OPERATOR_PHONE}" TEILER_ADMIN_PHONE: "${OPERATOR_PHONE}"
@ -42,8 +43,11 @@ services:
TEILER_ORCHESTRATOR_URL: "https://${HOST}/ccp-teiler" TEILER_ORCHESTRATOR_URL: "https://${HOST}/ccp-teiler"
TEILER_DASHBOARD_HTTP_RELATIVE_PATH: "/ccp-teiler-dashboard" TEILER_DASHBOARD_HTTP_RELATIVE_PATH: "/ccp-teiler-dashboard"
TEILER_ORCHESTRATOR_HTTP_RELATIVE_PATH: "/ccp-teiler" TEILER_ORCHESTRATOR_HTTP_RELATIVE_PATH: "/ccp-teiler"
TEILER_USER: "TEILER_USER" TEILER_USER: "${OIDC_USER_GROUP}"
TEILER_ADMIN: "TEILER_ADMIN" TEILER_ADMIN: "${OIDC_ADMIN_GROUP}"
REPORTER_DEFAULT_TEMPLATE_ID: "ccp-qb"
EXPORTER_DEFAULT_TEMPLATE_ID: "ccp"
teiler-backend: teiler-backend:
image: docker.verbis.dkfz.de/ccp/dktk-teiler-backend:latest image: docker.verbis.dkfz.de/ccp/dktk-teiler-backend:latest
@ -67,6 +71,8 @@ services:
TEILER_DASHBOARD_EN_URL: "https://${HOST}/ccp-teiler-dashboard/en" TEILER_DASHBOARD_EN_URL: "https://${HOST}/ccp-teiler-dashboard/en"
CENTRAX_URL: "${CENTRAXX_URL}" CENTRAX_URL: "${CENTRAXX_URL}"
HTTP_PROXY: "http://forward_proxy:3128" HTTP_PROXY: "http://forward_proxy:3128"
ENABLE_MTBA: "${ENABLE_MTBA}"
ENABLE_DATASHIELD: "${ENABLE_DATASHIELD}"
secrets: secrets:
- ccp.conf - ccp.conf

View File

@ -3,4 +3,7 @@
if [ "$ENABLE_TEILER" == true ];then if [ "$ENABLE_TEILER" == true ];then
log INFO "Teiler setup detected -- will start Teiler services." log INFO "Teiler setup detected -- will start Teiler services."
OVERRIDE+=" -f ./$PROJECT/modules/teiler-compose.yml" OVERRIDE+=" -f ./$PROJECT/modules/teiler-compose.yml"
DEFAULT_LANGUAGE=DE
DEFAULT_LANGUAGE_LOWER_CASE=${DEFAULT_LANGUAGE,,}
add_public_oidc_redirect_url "/ccp-teiler/*"
fi fi

View File

View File

@ -7,13 +7,20 @@ SUPPORT_EMAIL=support-ccp@dkfz-heidelberg.de
PRIVATEKEYFILENAME=/etc/bridgehead/pki/${SITE_ID}.priv.pem PRIVATEKEYFILENAME=/etc/bridgehead/pki/${SITE_ID}.priv.pem
BROKER_URL_FOR_PREREQ=$BROKER_URL BROKER_URL_FOR_PREREQ=$BROKER_URL
DEFAULT_LANGUAGE=DE
DEFAULT_LANGUAGE_LOWER_CASE=${DEFAULT_LANGUAGE,,}
ENABLE_EXPORTER=true
ENABLE_LOGIN=true
ENABLE_TEILER=true
#ENABLE_DATASHIELD=true
OIDC_USER_GROUP="DKTK_CCP_$(capitalize_first_letter ${SITE_ID})"
OIDC_ADMIN_GROUP="DKTK_CCP_$(capitalize_first_letter ${SITE_ID})_Verwalter"
OIDC_PRIVATE_CLIENT_ID=${SITE_ID}-private
OIDC_PUBLIC_CLIENT_ID=${SITE_ID}-public
# Use "test-realm-01" for testing
OIDC_REALM="${OIDC_REALM:-master}"
OIDC_URL="https://login.verbis.dkfz.de"
OIDC_ISSUER_URL="${OIDC_URL}/realms/${OIDC_REALM}"
OIDC_GROUP_CLAIM="groups"
OAUTH2_CALLBACK=/oauth2/callback
OAUTH2_PROXY_SECRET="$(echo \"This is a salt string to generate one consistent encryption key for the oauth2_proxy. It is not required to be secret.\" | openssl rsautl -sign -inkey /etc/bridgehead/pki/${SITE_ID}.priv.pem | base64 | head -c 32)"
add_private_oidc_redirect_url "${OAUTH2_CALLBACK}"
POSTGRES_TAG=15.6-alpine POSTGRES_TAG=15.6-alpine
for module in $PROJECT/modules/*.sh for module in $PROJECT/modules/*.sh

View File

@ -132,6 +132,12 @@ assertVarsNotEmpty() {
fixPermissions() { fixPermissions() {
CHOWN=$(which chown) CHOWN=$(which chown)
sudo $CHOWN -R bridgehead /etc/bridgehead /srv/docker/bridgehead sudo $CHOWN -R bridgehead /etc/bridgehead /srv/docker/bridgehead
if [ -d "/tmp/bridgehead" ]; then # Used by datashield
sudo $CHOWN -R bridgehead:docker "/tmp/bridgehead"
fi
if [ -d "/var/cache/bridgehead" ]; then # Used by the teiler
sudo $CHOWN -R bridgehead:docker "/var/cache/bridgehead"
fi
} }
source lib/monitoring.sh source lib/monitoring.sh
@ -239,3 +245,113 @@ add_basic_auth_user() {
log DEBUG "Saving clear text credentials in $FILE. If wanted, delete them manually." log DEBUG "Saving clear text credentials in $FILE. If wanted, delete them manually."
sed -i "/^$NAME/ s|$|\n# User: $USER\n# Password: $PASSWORD|" $FILE sed -i "/^$NAME/ s|$|\n# User: $USER\n# Password: $PASSWORD|" $FILE
} }
OIDC_PUBLIC_REDIRECT_URLS=${OIDC_PUBLIC_REDIRECT_URLS:-""}
OIDC_PRIVATE_REDIRECT_URLS=${OIDC_PRIVATE_REDIRECT_URLS:-""}
# Add a redirect url to the public oidc client of the bridgehead
function add_public_oidc_redirect_url() {
if [[ $OIDC_PUBLIC_REDIRECT_URLS == "" ]]; then
OIDC_PUBLIC_REDIRECT_URLS+="$(generate_redirect_urls $1)"
else
OIDC_PUBLIC_REDIRECT_URLS+=",$(generate_redirect_urls $1)"
fi
}
# Add a redirect url to the private oidc client of the bridgehead
function add_private_oidc_redirect_url() {
if [[ $OIDC_PRIVATE_REDIRECT_URLS == "" ]]; then
OIDC_PRIVATE_REDIRECT_URLS+="$(generate_redirect_urls $1)"
else
OIDC_PRIVATE_REDIRECT_URLS+=",$(generate_redirect_urls $1)"
fi
}
function sync_secrets() {
local delimiter=$'\x1E'
local secret_sync_args=""
if [[ $OIDC_PRIVATE_REDIRECT_URLS != "" ]]; then
secret_sync_args="OIDC:OIDC_CLIENT_SECRET:private;$OIDC_PRIVATE_REDIRECT_URLS"
fi
if [[ $OIDC_PRIVATE_REDIRECT_URLS != "" ]]; then
if [[ $secret_sync_args == "" ]]; then
secret_sync_args="OIDC:OIDC_PUBLIC:public;$OIDC_PUBLIC_REDIRECT_URLS"
else
secret_sync_args+="${delimiter}OIDC:OIDC_PUBLIC:public;$OIDC_PUBLIC_REDIRECT_URLS"
fi
fi
if [[ $secret_sync_args == "" ]]; then
return
fi
mkdir -p /var/cache/bridgehead/secrets/
touch /var/cache/bridgehead/secrets/oidc
docker run --rm \
-v /var/cache/bridgehead/secrets/oidc:/usr/local/cache \
-v $PRIVATEKEYFILENAME:/run/secrets/privkey.pem:ro \
-v /srv/docker/bridgehead/$PROJECT/root.crt.pem:/run/secrets/root.crt.pem:ro \
-v /etc/bridgehead/trusted-ca-certs:/conf/trusted-ca-certs:ro \
-e TLS_CA_CERTIFICATES_DIR=/conf/trusted-ca-certs \
-e NO_PROXY=localhost,127.0.0.1 \
-e ALL_PROXY=$HTTPS_PROXY_FULL_URL \
-e PROXY_ID=$PROXY_ID \
-e BROKER_URL=$BROKER_URL \
-e OIDC_PROVIDER=secret-sync-central.oidc-client-enrollment.$BROKER_ID \
-e SECRET_DEFINITIONS=$secret_sync_args \
docker.verbis.dkfz.de/cache/samply/secret-sync-local:latest
set -a # Export variables as environment variables
source /var/cache/bridgehead/secrets/*
set +a # Export variables in the regular way
}
capitalize_first_letter() {
input="$1"
capitalized="$(tr '[:lower:]' '[:upper:]' <<< ${input:0:1})${input:1}"
echo "$capitalized"
}
# Generate a string of ',' separated string of redirect urls relative to $HOST.
# $1 will be appended to the url
# If the host looks like dev-jan.inet.dkfz-heidelberg.de it will generate urls with dev-jan and the original $HOST as url Authorities
function generate_redirect_urls(){
local redirect_urls="https://${HOST}$1"
local host_without_proxy="$(echo "$HOST" | cut -d '.' -f1)"
# Only append second url if its different and the host is not an ip address
if [[ "$HOST" != "$host_without_proxy" && ! "$HOST" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
redirect_urls+=",https://$host_without_proxy$1"
fi
echo "$redirect_urls"
}
# This password contains at least one special char, a random number and a random upper and lower case letter
generate_password(){
local seed_text="$1"
local seed_num=$(awk 'BEGIN{FS=""} NR==1{print $10}' /etc/bridgehead/pki/${SITE_ID}.priv.pem | od -An -tuC)
local nums="1234567890"
local n=$(echo "$seed_num" | awk '{print $1 % 10}')
local random_digit=${nums:$n:1}
local n=$(echo "$seed_num" | awk '{print $1 % 26}')
local upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
local lower="abcdefghijklmnopqrstuvwxyz"
local random_upper=${upper:$n:1}
local random_lower=${lower:$n:1}
local n=$(echo "$seed_num" | awk '{print $1 % 8}')
local special='@#$%^&+='
local random_special=${special:$n:1}
local combined_text="This is a salt string to generate one consistent password for ${seed_text}. It is not required to be secret."
local main_password=$(echo "${combined_text}" | openssl rsautl -sign -inkey "/etc/bridgehead/pki/${SITE_ID}.priv.pem" 2> /dev/null | base64 | head -c 26 | sed 's/\//A/g')
echo "${main_password}${random_digit}${random_upper}${random_lower}${random_special}"
}
# This password only contains alphanumeric characters
generate_simple_password(){
local seed_text="$1"
local combined_text="This is a salt string to generate one consistent password for ${seed_text}. It is not required to be secret."
echo "${combined_text}" | openssl rsautl -sign -inkey "/etc/bridgehead/pki/${SITE_ID}.priv.pem" 2> /dev/null | base64 | head -c 26 | sed 's/[+\/]/A/g'
}
docker_jq() {
docker run --rm -i docker.verbis.dkfz.de/cache/jqlang/jq:latest "$@"
}

View File

@ -89,6 +89,9 @@ elif [[ "$DEV_MODE" == "DEV" ]]; then
fi fi
chown -R bridgehead /etc/bridgehead /srv/docker/bridgehead chown -R bridgehead /etc/bridgehead /srv/docker/bridgehead
mkdir -p /tmp/bridgehead /var/cache/bridgehead
chown -R bridgehead:docker /tmp/bridgehead /var/cache/bridgehead
chmod -R g+wr /var/cache/bridgehead /tmp/bridgehead
log INFO "System preparation is completed and configuration is present." log INFO "System preparation is completed and configuration is present."

View File

@ -42,6 +42,8 @@ services:
- /var/spool/squid - /var/spool/squid
volumes: volumes:
- /etc/bridgehead/trusted-ca-certs:/docker/custom-certs/:ro - /etc/bridgehead/trusted-ca-certs:/docker/custom-certs/:ro
healthcheck:
test: ["CMD", "sleep", "1"]
landing: landing:
container_name: bridgehead-landingpage container_name: bridgehead-landingpage
@ -55,5 +57,3 @@ services:
HOST: ${HOST} HOST: ${HOST}
PROJECT: ${PROJECT} PROJECT: ${PROJECT}
SITE_NAME: ${SITE_NAME} SITE_NAME: ${SITE_NAME}