From 79aba2b97a50f052e22d924633a758db50aa5beb Mon Sep 17 00:00:00 2001 From: Simon Schweizer Date: Mon, 18 Dec 2023 17:40:45 +0100 Subject: [PATCH 1/2] added documentation for 1.4.0 --- docs/src/.vuepress/theme.ts | 78 ++- docs/src/stable | 2 +- docs/src/v1.4.0/develop/README.md | 7 + docs/src/v1.4.0/develop/create.md | 10 + docs/src/v1.4.0/develop/upgrade-from-0.md | 10 + docs/src/v1.4.0/dsf-for-dev.md | 4 + docs/src/v1.4.0/index.md | 31 + docs/src/v1.4.0/maintain/README.md | 16 + docs/src/v1.4.0/maintain/allowList-mgm.md | 34 + docs/src/v1.4.0/maintain/bpe/README.md | 6 + docs/src/v1.4.0/maintain/bpe/configuration.md | 637 ++++++++++++++++++ .../maintain/fhir-reverse-proxy/README.md | 6 + .../fhir-reverse-proxy/configuration.md | 87 +++ docs/src/v1.4.0/maintain/fhir/README.md | 8 + .../v1.4.0/maintain/fhir/access-control.md | 129 ++++ .../src/v1.4.0/maintain/fhir/configuration.md | 392 +++++++++++ docs/src/v1.4.0/maintain/fhir/oidc.md | 63 ++ docs/src/v1.4.0/maintain/install-plugins.md | 21 + docs/src/v1.4.0/maintain/install.md | 232 +++++++ docs/src/v1.4.0/maintain/upgrade-from-0.md | 32 + docs/src/v1.4.0/maintain/upgrade-from-1.md | 71 ++ docs/src/v1.4.0/process-plugins-advanced.md | 4 + 22 files changed, 1875 insertions(+), 5 deletions(-) create mode 100644 docs/src/v1.4.0/develop/README.md create mode 100644 docs/src/v1.4.0/develop/create.md create mode 100644 docs/src/v1.4.0/develop/upgrade-from-0.md create mode 100644 docs/src/v1.4.0/dsf-for-dev.md create mode 100644 docs/src/v1.4.0/index.md create mode 100644 docs/src/v1.4.0/maintain/README.md create mode 100644 docs/src/v1.4.0/maintain/allowList-mgm.md create mode 100644 docs/src/v1.4.0/maintain/bpe/README.md create mode 100644 docs/src/v1.4.0/maintain/bpe/configuration.md create mode 100644 docs/src/v1.4.0/maintain/fhir-reverse-proxy/README.md create mode 100644 docs/src/v1.4.0/maintain/fhir-reverse-proxy/configuration.md create mode 100644 docs/src/v1.4.0/maintain/fhir/README.md create mode 100644 docs/src/v1.4.0/maintain/fhir/access-control.md create mode 100644 docs/src/v1.4.0/maintain/fhir/configuration.md create mode 100644 docs/src/v1.4.0/maintain/fhir/oidc.md create mode 100644 docs/src/v1.4.0/maintain/install-plugins.md create mode 100644 docs/src/v1.4.0/maintain/install.md create mode 100644 docs/src/v1.4.0/maintain/upgrade-from-0.md create mode 100644 docs/src/v1.4.0/maintain/upgrade-from-1.md create mode 100644 docs/src/v1.4.0/process-plugins-advanced.md diff --git a/docs/src/.vuepress/theme.ts b/docs/src/.vuepress/theme.ts index 3f8cf1d9a..87b83563e 100644 --- a/docs/src/.vuepress/theme.ts +++ b/docs/src/.vuepress/theme.ts @@ -39,7 +39,7 @@ export default hopeTheme({ prefix: "/stable/", children: [ { - text: "Guideline v1.3.2 (stable)", + text: "Guideline v1.4.0 (stable)", icon: "info", children: ["index", "maintain/install", "maintain/upgrade-from-0", "maintain/allowList-mgm", "maintain/install-plugins", "develop/create"], } @@ -62,7 +62,7 @@ export default hopeTheme({ text: "Versions", icon: "note", // children:["/v1/"], - children: [{ text: "v1.3.2 (stable)", link: "/stable/" }, { text: "v1.3.1", link: "/v1.3.1/" }, { text: "v1.3.0", link: "/v1.3.0/" }, { text: "v1.2.0", link: "/v1.2.0/" }, { text: "v1.1.0", link: "/v1.1.0/" }, { text: "v1.0.0", link: "/v1.0.0/" }, { text: "v0.9.3 (oldstable)", link: "/oldstable/"}], + children: [{ text: "v1.4.0 (stable)", link: "/stable/" }, { text: "v1.3.2", link: "/v1.3.2/" }, { text: "v1.3.1", link: "/v1.3.1/" }, { text: "v1.3.0", link: "/v1.3.0/" }, { text: "v1.2.0", link: "/v1.2.0/" }, { text: "v1.1.0", link: "/v1.1.0/" }, { text: "v1.0.0", link: "/v1.0.0/" }, { text: "v0.9.3 (oldstable)", link: "/oldstable/"}], }, { text: "", @@ -171,7 +171,7 @@ export default hopeTheme({ children: ["create", "upgrade-from-0" ], }, ], - "/v1.3.2/": [ + "/v1.4.0/": [ { text: "Home", icon: "home", @@ -236,6 +236,75 @@ export default hopeTheme({ children: ["create", "upgrade-from-0" ], }, ], + "/v1.3.2/": [ + { + text: "Home", + icon: "home", + link: "/", + }, + { + text: "Current version", + icon: "update", + link: "/stable", + }, + { + text: "Maintain a DSF instance", + icon: "tool", + prefix: "maintain/", + link: "maintain/", + children: ["install", "upgrade-from-1", "upgrade-from-0", "allowList-mgm", { + text: "FHIR Reverse Proxy", + icon: "module", + prefix: "fhir-reverse-proxy/", + link: "fhir-reverse-proxy/", + children: [{ + icon: "config", + text: "Configuration", + link: "configuration" + }] + }, { + text: "FHIR Server", + icon: "module", + prefix: "fhir/", + link: "fhir/", + children: [{ + icon: "config", + text: "Configuration", + link: "configuration" + }, { + icon: "config", + text: "Access Control", + link: "access-control" + }, { + icon: "config", + text: "OpenID Connect", + link: "oidc" + }] + }, { + text: "BPE Server", + icon: "module", + prefix: "bpe/", + link: "bpe/", + children: [{ + icon: "config", + text: "Configuration", + link: "configuration" + }] + }, + { + text: "Install Plugins", + icon: "plugin", + link: "install-plugins" + }], + }, + { + text: "Develop process plugins", + icon: "plugin", + prefix: "develop/", + link: "develop/", + children: ["create", "upgrade-from-0" ], + }, + ], "/v1.3.1/": [ { text: "Home", @@ -246,7 +315,8 @@ export default hopeTheme({ text: "Current version", icon: "update", link: "/stable", - }, { + }, + { text: "Maintain a DSF instance", icon: "tool", prefix: "maintain/", diff --git a/docs/src/stable b/docs/src/stable index bb8edae97..ec7b96782 120000 --- a/docs/src/stable +++ b/docs/src/stable @@ -1 +1 @@ -v1.3.2 \ No newline at end of file +v1.4.0 \ No newline at end of file diff --git a/docs/src/v1.4.0/develop/README.md b/docs/src/v1.4.0/develop/README.md new file mode 100644 index 000000000..7c7613cb5 --- /dev/null +++ b/docs/src/v1.4.0/develop/README.md @@ -0,0 +1,7 @@ +--- +title: Develop Process Plugins +icon: plugin +--- +## Overview +- [Create a new process plugin](create) +- [Upgrade processes from 0.9.x](upgrade-from-0) \ No newline at end of file diff --git a/docs/src/v1.4.0/develop/create.md b/docs/src/v1.4.0/develop/create.md new file mode 100644 index 000000000..3a99e69b1 --- /dev/null +++ b/docs/src/v1.4.0/develop/create.md @@ -0,0 +1,10 @@ +--- +title: Create a new process plugin +icon: code +--- +::: tip Work in progress +We are currently in the process of updating the written documentation on how to create a DSF process plugin. In the meantime we recommend to study the oldstable version of the [process plugin tutorial](/oldstable/tutorial/). Additionally, we recommend to take a look at the upgraded DSF processes here: +- The [hello world plugin](https://github.com/datasharingframework/dsf-process-hello-world) +- The [ping pong plugin](https://github.com/datasharingframework/dsf-process-ping-pong) +- The [update allowlist plugin](https://github.com/datasharingframework/dsf-process-allow-list) +::: \ No newline at end of file diff --git a/docs/src/v1.4.0/develop/upgrade-from-0.md b/docs/src/v1.4.0/develop/upgrade-from-0.md new file mode 100644 index 000000000..d27d7a228 --- /dev/null +++ b/docs/src/v1.4.0/develop/upgrade-from-0.md @@ -0,0 +1,10 @@ +--- +title: Upgrade processes from 0.9.x +icon: update +--- +::: tip Work in progress +We are currently in the process of updating the written documentation on how to upgrade a DSF process plugin to DSF 1.0.0. In the meantime we recommend to take a look at the provided sample plugin and the upgraded DSF plugins: +- The [hello world plugin](https://github.com/datasharingframework/dsf-process-hello-world) +- The [ping pong plugin](https://github.com/datasharingframework/dsf-process-ping-pong) +- The [update allowlist plugin](https://github.com/datasharingframework/dsf-process-allow-list) +::: \ No newline at end of file diff --git a/docs/src/v1.4.0/dsf-for-dev.md b/docs/src/v1.4.0/dsf-for-dev.md new file mode 100644 index 000000000..45e408ca1 --- /dev/null +++ b/docs/src/v1.4.0/dsf-for-dev.md @@ -0,0 +1,4 @@ +--- +title: DSF for Developers +icon: info +--- \ No newline at end of file diff --git a/docs/src/v1.4.0/index.md b/docs/src/v1.4.0/index.md new file mode 100644 index 000000000..0edb94855 --- /dev/null +++ b/docs/src/v1.4.0/index.md @@ -0,0 +1,31 @@ +--- +title: DSF 1.4.0 +icon: guide +--- + +Data Sharing Framework 1.x is the new major release of the Data Sharing Framework. Click [here](/intro/) to find more information about the DSF in general. +::: tip Important note +This is a major DSF release not compatible with 0.9.x and older version developed at https://github.com/highmed/highmed-dsf. +::: + +# System Administrators + +- [Upgrade from DSF 0.9.x.](maintain/upgrade-from-0) +- [Upgrade from DSF 1.3.2](maintain/upgrade-from-1) +- [Install DSF 1.4.0](maintain/install) + + +# Developers +- [Create a new process plugin](develop/create) +- [Upgrade from DSF 0.9.x.](develop/upgrade-from-0) + +## New features +- Improved versioning to support up- and downwards-compatibility +- Enhanced web ui to start processes in the web browser +- Allow local user authentication and authorization with OpenID Connect +- New process plugin API +- Removed mostly unused features to simplify instance configuration +- Unified proxy setup +- Many more features, see [1.x release-notes](https://github.com/datasharingframework/dsf/releases) + + diff --git a/docs/src/v1.4.0/maintain/README.md b/docs/src/v1.4.0/maintain/README.md new file mode 100644 index 000000000..b3f4582b1 --- /dev/null +++ b/docs/src/v1.4.0/maintain/README.md @@ -0,0 +1,16 @@ +--- +title: Maintain a DSF instance +icon: tool +--- +## Overview +- [Install DSF 1.4.0](install) +- [Upgrade from DSF 0.9.x](upgrade-from-0) +- [Allow List Management](allowList-mgm) +- FHIR Reverse Proxy + - [Configuration Parameters](fhir-reverse-proxy/configuration) +- FHIR Server + - [Configuration Parameters](fhir/configuration) + - [Access Control](fhir/access-control) + - [OpenID Connect](fhir/oidc) +- BPE Server + - [Configuration Parameters](bpe/configuration) diff --git a/docs/src/v1.4.0/maintain/allowList-mgm.md b/docs/src/v1.4.0/maintain/allowList-mgm.md new file mode 100644 index 000000000..d04ae8c54 --- /dev/null +++ b/docs/src/v1.4.0/maintain/allowList-mgm.md @@ -0,0 +1,34 @@ +--- +title: Allow List Management +icon: share +--- +You can read all about the concept of Allow Lists [in our introduction](/intro/info/allowList.md). + +## Overview +To simplify the DSF Allow List Management we have built a portal for administration. The portal is managed by the GECKO Institute at Heilbronn University. You as an DSF administrator can create or update your Allow List information. The information you provide on this portal will be transferred to us and will be used to built Allow List bundles that get distributed to the communication partners of the distributed processes. + +The DSF Allow List management tool uses client certificates for authentication. You can either use a personal client certificate or the client certificate from your DSF BPE, which needs to be added to your web-browsers certificate store. + + +## Prerequisites +1. Deployed DSF instance (test or production infrastructure) + 1.1 If none exists yet, read [the installation guide](install) +2. Certificate + 2.1 If none exists yet, read [the certificate requirements](install#client-server-certificates) +3. Organization identifier, shortest FQDN of your organizations website, e.g. `my-hospital.de` +4. FHIR endpoint URL, e.g. `https://dsf.my-hospital.de/fhir` +5. Contact details from a responsible person of your organization +6. Access to the E-Mail address from your organization for verification + + +## Start here +When you have fulfilled all the prerequisites, you can start managing your Allow Lists via the environment specific Allow List Management Tool: + +- [**Test** infrastructure](https://allowlist-test.gecko.hs-heilbronn.de) +- [**Production** infrastructure](https://allowlist.gecko.hs-heilbronn.de) + +We use different highlight colors for the DSF Allow List Management Tool: Green for the **Test** environment and blue for the **Production** infrastructure. To access the site, you have to authenticate yourself with a client certificate. Your web-browser will show a dialog to choose a valid certificate. + +::: tip Ideas for improvement? +Have you found an error or is something unclear to you? Then please feel free to contact us on the MII-Zulip Channel or write us at gth-gecko@hs-heilbronn.de. Thank you very much! +::: \ No newline at end of file diff --git a/docs/src/v1.4.0/maintain/bpe/README.md b/docs/src/v1.4.0/maintain/bpe/README.md new file mode 100644 index 000000000..565228aef --- /dev/null +++ b/docs/src/v1.4.0/maintain/bpe/README.md @@ -0,0 +1,6 @@ +--- +title: BPE Server +icon: module +--- +## Overview +- [Configuration Parameters](configuration) diff --git a/docs/src/v1.4.0/maintain/bpe/configuration.md b/docs/src/v1.4.0/maintain/bpe/configuration.md new file mode 100644 index 000000000..4327ddef6 --- /dev/null +++ b/docs/src/v1.4.0/maintain/bpe/configuration.md @@ -0,0 +1,637 @@ +--- +title: Configuration Parameters +icon: config +--- + +### DEV_DSF_SERVER_API_HOST +- **Property:** dev.dsf.server.api.host +- **Required:** Yes +- **Description:** API connector host, default in docker image: `0.0.0.0` +- **Default:** `127.0.0.1` + + +### DEV_DSF_SERVER_API_PORT +- **Property:** dev.dsf.server.api.port +- **Required:** Yes +- **Description:** API connector port, default in docker image: `8080` + + +### DEV_DSF_SERVER_AUTH_CLIENT_CERTIFICATE_HEADER +- **Property:** dev.dsf.server.auth.client.certificate.header +- **Required:** Yes +- **Description:** Name of HTTP header with client certificate from reverse proxy +- **Default:** `X-ClientCert` + + +### DEV_DSF_SERVER_AUTH_OIDC_AUTHORIZATION_CODE_FLOW +- **Property:** dev.dsf.server.auth.oidc.authorization.code.flow +- **Required:** No +- **Description:** Set to `true` to enable OIDC authorization code flow +- **Recommendation:** Requires *DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_REALM_BASE_URL*, *DEV_DSF_SERVER_AUTH_OIDC_CLIENT_ID* and *DEV_DSF_SERVER_AUTH_OIDC_CLIENT_SECRET* to be specified +- **Default:** `false` + + +### DEV_DSF_SERVER_AUTH_OIDC_BACK_CHANNEL_LOGOUT +- **Property:** dev.dsf.server.auth.oidc.back.channel.logout +- **Required:** No +- **Description:** Set to `true` to enable OIDC back-channel logout +- **Recommendation:** Requires *DEV_DSF_SERVER_AUTH_OIDC_AUTHORIZATION_CODE_FLOW* to be set to `true` (enabled), *DEV_DSF_SERVER_AUTH_OIDC_CLIENT_ID* and *DEV_DSF_SERVER_AUTH_OIDC_BACK_CHANNEL_LOGOUT_PATH* to be specified +- **Default:** `false` + + +### DEV_DSF_SERVER_AUTH_OIDC_BACK_CHANNEL_LOGOUT_PATH +- **Property:** dev.dsf.server.auth.oidc.back.channel.logout.path +- **Required:** No +- **Description:** Path called by the OIDC provide to request back-channel logout +- **Default:** `/back-channel-logout` + + +### DEV_DSF_SERVER_AUTH_OIDC_BEARER_TOKEN +- **Property:** dev.dsf.server.auth.oidc.bearer.token +- **Required:** No +- **Description:** Set to `true` to enable OIDC bearer token authentication +- **Recommendation:** Requires *DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_REALM_BASE_URL* to be specified +- **Default:** `false` + + +### DEV_DSF_SERVER_AUTH_OIDC_CLIENT_ID +- **Property:** dev.dsf.server.auth.oidc.client.id +- **Required:** No +- **Description:** OIDC provider client_id, must be specified if *DEV_DSF_SERVER_AUTH_OIDC_AUTHORIZATION_CODE_FLOW* is enabled + + +### DEV_DSF_SERVER_AUTH_OIDC_CLIENT_SECRET +- **Property:** dev.dsf.server.auth.oidc.client.secret +- **Required:** No +- **Description:** OIDC provider client_secret, must be specified if *DEV_DSF_SERVER_AUTH_OIDC_AUTHORIZATION_CODE_FLOW* is enabled + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE +- **Property:** dev.dsf.server.auth.oidc.provider.client.certificate +- **Required:** No +- **Description:** PEM encoded file with client certificate for https connections to the OIDC provider +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/oidc_provider_client_certificate.pem` + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE_PRIVATE_KEY +- **Property:** dev.dsf.server.auth.oidc.provider.client.certificate.private.key +- **Required:** No +- **Description:** Private key corresponding to the client certificate for the OIDC provider as PEM encoded file. Use *DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD* or *DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE* if private key is encrypted +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/oidc_provider_client_certificate_private_key.pem` + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD or DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE +- **Property:** dev.dsf.server.auth.oidc.provider.client.certificate.private.key.password +- **Required:** No +- **Description:** Password to decrypt the client certificate for the OIDC provider encrypted private key +- **Recommendation:** Use docker secret file to configure using *DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE* +- **Example:** `/run/secrets/oidc_provider_client_certificate_private_key.pem.password` + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CONNECTTIMEOUT +- **Property:** dev.dsf.server.auth.oidc.provider.client.connectTimeout +- **Required:** No +- **Description:** OIDC provider client connect timeout in milliseconds +- **Default:** `5000` + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_IDLETIMEOUT +- **Property:** dev.dsf.server.auth.oidc.provider.client.idleTimeout +- **Required:** No +- **Description:** OIDC provider client idle timeout in milliseconds +- **Default:** `30000` + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_TRUST_SERVER_CERTIFICATE_CAS +- **Property:** dev.dsf.server.auth.oidc.provider.client.trust.server.certificate.cas +- **Required:** No +- **Description:** PEM encoded file with one or more trusted root certificates to validate server certificates for https connections to the OIDC provider +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/oidc_provider_trust_certificates.pem` + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_REALM_BASE_URL +- **Property:** dev.dsf.server.auth.oidc.provider.realm.base.url +- **Required:** No +- **Description:** OIDC provider realm base url +- **Example:** `https://keycloak.test.com:8443/realms/example-realm-name` + + +### DEV_DSF_SERVER_AUTH_TRUST_CLIENT_CERTIFICATE_CAS +- **Property:** dev.dsf.server.auth.trust.client.certificate.cas +- **Required:** Yes +- **Description:** PEM encoded file with one or more trusted root certificates to validate client certificates for https connections from local and remote clients +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/app_client_trust_certificates.pem` + + +### DEV_DSF_SERVER_CERTIFICATE +- **Property:** dev.dsf.server.certificate +- **Required:** No +- **Description:** Server certificate file for testing +- **Recommendation:** Only specify For testing when terminating TLS in jetty server + + +### DEV_DSF_SERVER_CERTIFICATE_CHAIN +- **Property:** dev.dsf.server.certificate.chain +- **Required:** No +- **Description:** Server certificate chain file for testing +- **Recommendation:** Only specify For testing when terminating TLS in jetty server + + +### DEV_DSF_SERVER_CERTIFICATE_KEY +- **Property:** dev.dsf.server.certificate.key +- **Required:** No +- **Description:** Server certificate private key file for testing +- **Recommendation:** Only specify For testing when terminating TLS in jetty server + + +### DEV_DSF_SERVER_CERTIFICATE_KEY_PASSWORD or DEV_DSF_SERVER_CERTIFICATE_KEY_PASSWORD_FILE +- **Property:** dev.dsf.server.certificate.key.password +- **Required:** No +- **Description:** Server certificate private key file password for testing +- **Recommendation:** Only specify For testing when terminating TLS in jetty server + + +### DEV_DSF_SERVER_CONTEXT_PATH +- **Property:** dev.dsf.server.context.path +- **Required:** Yes +- **Description:** Web application context path, default in `bpe` docker image: `/bpe`, default in `fhir` docker image: `/fhir` +- **Recommendation:** Only modify for testing + + +### DEV_DSF_SERVER_STATUS_HOST +- **Property:** dev.dsf.server.status.host +- **Required:** Yes +- **Description:** Status connector host +- **Default:** `127.0.0.1` + + +### DEV_DSF_SERVER_STATUS_PORT +- **Property:** dev.dsf.server.status.port +- **Required:** Yes +- **Description:** Status connector port, default in docker image: `10000` + + +### DEV_DSF_BPE_DB_LIQUIBASE_FORCEUNLOCK +- **Property:** dev.dsf.bpe.db.liquibase.forceUnlock +- **Required:** No +- **Description:** To force liquibase to unlock the migration lock set to `true` +- **Recommendation:** Only use this option temporarily to unlock a stuck DB migration step +- **Default:** `false` + + +### DEV_DSF_BPE_DB_LIQUIBASE_LOCKWAITTIME +- **Property:** dev.dsf.bpe.db.liquibase.lockWaitTime +- **Required:** No +- **Description:** Liquibase change lock wait time in minutes, default 2 minutes +- **Default:** `2` + + +### DEV_DSF_BPE_DB_LIQUIBASE_PASSWORD or DEV_DSF_BPE_DB_LIQUIBASE_PASSWORD_FILE +- **Property:** dev.dsf.bpe.db.liquibase.password +- **Required:** Yes +- **Description:** The password to access the database from the DSF BPE server to execute database migrations +- **Recommendation:** Use docker secret file to configure by using *DEV_DSF_BPE_DB_LIQUIBASE_PASSWORD_FILE* +- **Example:** `/run/secrets/db_liquibase.password` + + +### DEV_DSF_BPE_DB_LIQUIBASE_USERNAME +- **Property:** dev.dsf.bpe.db.liquibase.username +- **Required:** No +- **Description:** The user name to access the database from the DSF BPE server to execute database migrations +- **Default:** `liquibase_user` + + +### DEV_DSF_BPE_DB_URL +- **Property:** dev.dsf.bpe.db.url +- **Required:** Yes +- **Description:** The address of the database used for the DSF BPE server +- **Recommendation:** Change only if you don't use the provided docker-compose from the installation guide or made changes to the database settings/networking in the docker-compose +- **Example:** `jdbc:postgresql://db/bpe` + + +### DEV_DSF_BPE_DB_USER_CAMUNDA_GROUP +- **Property:** dev.dsf.bpe.db.user.camunda.group +- **Required:** No +- **Description:** The name of the user group to access the database from the DSF BPE server for camunda processes +- **Default:** `camunda_users` + + +### DEV_DSF_BPE_DB_USER_CAMUNDA_PASSWORD or DEV_DSF_BPE_DB_USER_CAMUNDA_PASSWORD_FILE +- **Property:** dev.dsf.bpe.db.user.camunda.password +- **Required:** Yes +- **Description:** The password to access the database from the DSF BPE server for camunda processes +- **Recommendation:** Use docker secret file to configure using *DEV_DSF_BPE_DB_USER_CAMUNDA_PASSWORD_FILE* +- **Example:** `/run/secrets/db_user_camunda.password` + + +### DEV_DSF_BPE_DB_USER_CAMUNDA_USERNAME +- **Property:** dev.dsf.bpe.db.user.camunda.username +- **Required:** No +- **Description:** The user name to access the database from the DSF BPE server for camunda processes +- **Recommendation:** Use a different user then in *DEV_DSF_BPE_DB_USER_USERNAME* +- **Default:** `camunda_server_user` + + +### DEV_DSF_BPE_DB_USER_GROUP +- **Property:** dev.dsf.bpe.db.user.group +- **Required:** No +- **Description:** The name of the user group to access the database from the DSF BPE server +- **Default:** `bpe_users` + + +### DEV_DSF_BPE_DB_USER_PASSWORD or DEV_DSF_BPE_DB_USER_PASSWORD_FILE +- **Property:** dev.dsf.bpe.db.user.password +- **Required:** Yes +- **Description:** The password to access the database from the DSF BPE server +- **Recommendation:** Use docker secret file to configure using *DEV_DSF_BPE_DB_USER_PASSWORD_FILE* +- **Example:** `/run/secrets/db_user.password` + + +### DEV_DSF_BPE_DB_USER_USERNAME +- **Property:** dev.dsf.bpe.db.user.username +- **Required:** No +- **Description:** The user name to access the database from the DSF BPE server +- **Default:** `bpe_server_user` + + +### DEV_DSF_BPE_DEBUG_LOG_MESSAGE_ONACTIVITYEND +- **Property:** dev.dsf.bpe.debug.log.message.onActivityEnd +- **Required:** No +- **Description:** To enable debug log messages for every bpmn activity end, set to `true`. +- **Recommendation:** This debug function should only be activated during process plugin development. +- **Default:** `false` + + +### DEV_DSF_BPE_DEBUG_LOG_MESSAGE_ONACTIVITYSTART +- **Property:** dev.dsf.bpe.debug.log.message.onActivityStart +- **Required:** No +- **Description:** To enable debug log messages for every bpmn activity start, set to `true`. +- **Recommendation:** This debug function should only be activated during process plugin development. +- **Default:** `false` + + +### DEV_DSF_BPE_DEBUG_LOG_MESSAGE_VARIABLES +- **Property:** dev.dsf.bpe.debug.log.message.variables +- **Required:** No +- **Description:** To enable logging of bpmn variables for every bpmn activity start or end, when logging of these events is enabled, set to `true`. +- **Recommendation:** This debug function should only be activated during process plugin development. WARNNING: Confidential information may be leaked via the debug log! +- **Default:** `false` + + +### DEV_DSF_BPE_DEBUG_LOG_MESSAGE_VARIABLESLOCAL +- **Property:** dev.dsf.bpe.debug.log.message.variablesLocal +- **Required:** No +- **Description:** To enable logging of local bpmn variables for every bpmn activity start or end, when logging of these events is enabled, set to `true`. +- **Recommendation:** This debug function should only be activated during process plugin development. WARNNING: Confidential information may be leaked via the debug log! +- **Default:** `false` + + +### DEV_DSF_BPE_FHIR_CLIENT_CERTIFICATE +- **Property:** dev.dsf.bpe.fhir.client.certificate +- **Required:** Yes +- **Description:** PEM encoded file with local client certificate for https connections to local and remote DSF FHIR servers +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/app_client_certificate.pem` + + +### DEV_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY +- **Property:** dev.dsf.bpe.fhir.client.certificate.private.key +- **Required:** Yes +- **Description:** Private key corresponding to the local client certificate as PEM encoded file. Use DEV_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD* or *DEV_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE* if private key is encrypted +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/app_client_certificate_private_key.pem` + + +### DEV_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD or DEV_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE +- **Property:** dev.dsf.bpe.fhir.client.certificate.private.key.password +- **Required:** No +- **Description:** Password to decrypt the local client certificate encrypted private key +- **Recommendation:** Use docker secret file to configure using *DEV_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE* +- **Example:** `/run/secrets/app_client_certificate_private_key.pem.password` + + +### DEV_DSF_BPE_FHIR_CLIENT_LOCAL_TIMEOUT_CONNECT +- **Property:** dev.dsf.bpe.fhir.client.local.timeout.connect +- **Required:** No +- **Description:** The timeout in milliseconds until a connection is established with the local DSF FHIR server +- **Recommendation:** Change default value only if timeout exceptions occur +- **Default:** `2000` + + +### DEV_DSF_BPE_FHIR_CLIENT_LOCAL_TIMEOUT_READ +- **Property:** dev.dsf.bpe.fhir.client.local.timeout.read +- **Required:** No +- **Description:** The timeout in milliseconds until reading a resource from the local DSF FHIR server is aborted +- **Recommendation:** Change default value only if timeout exceptions occur +- **Default:** `60000` + + +### DEV_DSF_BPE_FHIR_CLIENT_LOCAL_VERBOSE +- **Property:** dev.dsf.bpe.fhir.client.local.verbose +- **Required:** No +- **Description:** To enable verbose logging of requests to and replies from the local DSF FHIR server, set to `true` +- **Default:** `false` + + +### DEV_DSF_BPE_FHIR_CLIENT_REMOTE_TIMEOUT_CONNECT +- **Property:** dev.dsf.bpe.fhir.client.remote.timeout.connect +- **Required:** No +- **Description:** The timeout in milliseconds until a connection is established with a remote DSF FHIR server +- **Recommendation:** Change default value only if timeout exceptions occur +- **Default:** `5000` + + +### DEV_DSF_BPE_FHIR_CLIENT_REMOTE_TIMEOUT_READ +- **Property:** dev.dsf.bpe.fhir.client.remote.timeout.read +- **Required:** No +- **Description:** The timeout in milliseconds until a reading a resource from a remote DSF FHIR server is aborted +- **Recommendation:** Change default value only if timeout exceptions occur +- **Default:** `60000` + + +### DEV_DSF_BPE_FHIR_CLIENT_REMOTE_VERBOSE +- **Property:** dev.dsf.bpe.fhir.client.remote.verbose +- **Required:** No +- **Description:** To enable verbose logging of requests to and replies from remote DSF FHIR servers, set to `true` +- **Default:** `false` + + +### DEV_DSF_BPE_FHIR_CLIENT_TRUST_SERVER_CERTIFICATE_CAS +- **Property:** dev.dsf.bpe.fhir.client.trust.server.certificate.cas +- **Required:** Yes +- **Description:** PEM encoded file with one or more trusted root certificates to validate server certificates for https connections to local and remote DSF FHIR servers +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/app_client_trust_certificates.pem` + + +### DEV_DSF_BPE_FHIR_QUESTIONNAIRE_RESPONSE_SUBSCRIPTION_SEARCH_PARAMETER +- **Property:** dev.dsf.bpe.fhir.questionnaire.response.subscription.search.parameter +- **Required:** No +- **Description:** Subscription to receive notifications about questionnaire response resources from the DSF FHIR server +- **Default:** `?criteria=QuestionnaireResponse%3Fstatus%3Dcompleted&status=active&type=websocket&payload=application/fhir%2Bjson` + + +### DEV_DSF_BPE_FHIR_SERVER_BASE_URL +- **Property:** dev.dsf.bpe.fhir.server.base.url +- **Required:** Yes +- **Description:** The base address of the local DSF FHIR server to read/store fhir resources +- **Example:** `https://foo.bar/fhir` + + +### DEV_DSF_BPE_FHIR_TASK_SUBSCRIPTION_RETRY_MAX +- **Property:** dev.dsf.bpe.fhir.task.subscription.retry.max +- **Required:** No +- **Description:** Number of retries until a websocket connection can be established with the DSF FHIR server, `-1` means infinite number of retries +- **Default:** `-1` + + +### DEV_DSF_BPE_FHIR_TASK_SUBSCRIPTION_RETRY_SLEEP +- **Property:** dev.dsf.bpe.fhir.task.subscription.retry.sleep +- **Required:** No +- **Description:** Milliseconds between two retries to establish a websocket connection with the DSF FHIR server +- **Default:** `5000` + + +### DEV_DSF_BPE_FHIR_TASK_SUBSCRIPTION_SEARCH_PARAMETER +- **Property:** dev.dsf.bpe.fhir.task.subscription.search.parameter +- **Required:** No +- **Description:** Subscription to receive notifications about task resources from the DSF FHIR server +- **Default:** `?criteria=Task%3Fstatus%3Drequested&status=active&type=websocket&payload=application/fhir%2Bjson` + + +### DEV_DSF_BPE_MAIL_CLIENT_CERTIFICATE +- **Property:** dev.dsf.bpe.mail.client.certificate +- **Required:** No +- **Description:** PEM encoded file with client certificate used to authenticate against the SMTP server. Requires SMTP over TLS to be enabled via *DEV_DSF_BPE_MAIL_USESMTPS* +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/smtp_server_client_certificate.pem` + + +### DEV_DSF_BPE_MAIL_CLIENT_CERTIFICATE_PRIVATE_KEY +- **Property:** dev.dsf.bpe.mail.client.certificate.private.key +- **Required:** No +- **Description:** Private key corresponging to the SMTP server client certificate as PEM encoded file. Use DEV_DSF_BPE_MAIL_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD* or *DEV_DSF_BPE_MAIL_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE* if private key is encrypted. Requires SMTP over TLS to be enabled via *DEV_DSF_BPE_MAIL_USESMTPS* +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/smtp_server_client_certificate_private_key.pem` + + +### DEV_DSF_BPE_MAIL_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD or DEV_DSF_BPE_MAIL_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE +- **Property:** dev.dsf.bpe.mail.client.certificate.private.key.password +- **Required:** No +- **Description:** Password to decrypt the local client certificate encrypted private key +- **Recommendation:** Use docker secret file to configure using *DEV_DSF_BPE_MAIL_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE* +- **Example:** `/run/secrets/smtp_server_client_certificate_private_key.pem.password` + + +### DEV_DSF_BPE_MAIL_FROMADDRESS +- **Property:** dev.dsf.bpe.mail.fromAddress +- **Required:** No +- **Description:** Mail service sender address +- **Example:** `sender@localhost` + + +### DEV_DSF_BPE_MAIL_HOST +- **Property:** dev.dsf.bpe.mail.host +- **Required:** No +- **Description:** SMTP server hostname +- **Example:** `smtp.server.de` + + +### DEV_DSF_BPE_MAIL_MAILONERRORLOGEVENTBUFFERSIZE +- **Property:** dev.dsf.bpe.mail.mailOnErrorLogEventBufferSize +- **Required:** No +- **Description:** Number of previous INFO, WARN log messages to include in ERROR log event mails (>=0). Requires send mail on ERROR log event option to be enabled to have an effect. +- **Default:** `4` + + +### DEV_DSF_BPE_MAIL_MAILONERRORLOGEVENTDEBUGLOGLOCATION +- **Property:** dev.dsf.bpe.mail.mailOnErrorLogEventDebugLogLocation +- **Required:** No +- **Description:** Location of the BPE debug log as displayed in the footer of ERROR log event mails, does not modify the actual location of the debug log file. Requires send mail on ERROR log event option to be enabled to have an effect. +- **Default:** `/opt/bpe/log/bpe.log` + + +### DEV_DSF_BPE_MAIL_PASSWORD or DEV_DSF_BPE_MAIL_PASSWORD_FILE +- **Property:** dev.dsf.bpe.mail.password +- **Required:** No +- **Description:** SMTP server authentication password +- **Recommendation:** Configure if the SMTP server reqiures username/password authentication; use docker secret file to configure using *DEV_DSF_BPE_MAIL_PASSWORD_FILE*; enable SMTP over TLS via *DEV_DSF_BPE_MAIL_USESMTPS* + + +### DEV_DSF_BPE_MAIL_PORT +- **Property:** dev.dsf.bpe.mail.port +- **Required:** No +- **Description:** SMTP server port +- **Example:** `465` +- **Default:** `0` + + +### DEV_DSF_BPE_MAIL_REPLYTOADDRESSES +- **Property:** dev.dsf.bpe.mail.replyToAddresses +- **Required:** No +- **Description:** Mail service reply to addresses; comma or space separated list, YAML block scalars supported +- **Example:** `reply.to@localhost` + + +### DEV_DSF_BPE_MAIL_SENDMAILONERRORLOGEVENT +- **Property:** dev.dsf.bpe.mail.sendMailOnErrorLogEvent +- **Required:** No +- **Description:** To enable mails being send for every ERROR logged, set to `true`. Requires SMTP server to be configured. +- **Default:** `false` + + +### DEV_DSF_BPE_MAIL_SENDTESTMAILONSTARTUP +- **Property:** dev.dsf.bpe.mail.sendTestMailOnStartup +- **Required:** No +- **Description:** To enable a test mail being send on startup of the BPE, set to `true`. Requires SMTP server to be configured. +- **Default:** `false` + + +### DEV_DSF_BPE_MAIL_SMIME_P12KEYSTORE +- **Property:** dev.dsf.bpe.mail.smime.p12Keystore +- **Required:** No +- **Description:** PKCS12 encoded file with S/MIME certificate, private key and certificate chain to enable send mails to be S/MIME signed +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/smime_certificate.p12` + + +### DEV_DSF_BPE_MAIL_SMIME_P12KEYSTORE_PASSWORD or DEV_DSF_BPE_MAIL_SMIME_P12KEYSTORE_PASSWORD_FILE +- **Property:** dev.dsf.bpe.mail.smime.p12Keystore.password +- **Required:** No +- **Description:** Password to decrypt the PKCS12 encoded S/MIMIE certificate file +- **Recommendation:** Use docker secret file to configure using *DEV_DSF_BPE_MAIL_SMIME_P12KEYSTORE_PASSWORD_FILE* +- **Example:** `/run/secrets/smime_certificate.p12.password` + + +### DEV_DSF_BPE_MAIL_TOADDRESSES +- **Property:** dev.dsf.bpe.mail.toAddresses +- **Required:** No +- **Description:** Mail service recipient addresses, configure at least one; comma or space separated list, YAML block scalars supported +- **Example:** `recipient@localhost` + + +### DEV_DSF_BPE_MAIL_TOADDRESSESCC +- **Property:** dev.dsf.bpe.mail.toAddressesCc +- **Required:** No +- **Description:** Mail service CC recipient addresses; comma or space separated list, YAML block scalars supported +- **Example:** `cc.recipient@localhost` + + +### DEV_DSF_BPE_MAIL_TRUST_SERVER_CERTIFICATE_CAS +- **Property:** dev.dsf.bpe.mail.trust.server.certificate.cas +- **Required:** No +- **Description:** PEM encoded file with one or more trusted root certificates to validate the server certificate of the SMTP server. Requires SMTP over TLS to be enabled via *DEV_DSF_BPE_MAIL_USESMTPS* +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/smtp_server_trust_certificates.pem` + + +### DEV_DSF_BPE_MAIL_USERNAME +- **Property:** dev.dsf.bpe.mail.username +- **Required:** No +- **Description:** SMTP server authentication username +- **Recommendation:** Configure if the SMTP server reqiures username/password authentication; enable SMTP over TLS via *DEV_DSF_BPE_MAIL_USESMTPS* + + +### DEV_DSF_BPE_MAIL_USESMTPS +- **Property:** dev.dsf.bpe.mail.useSmtps +- **Required:** No +- **Description:** To enable SMTP over TLS (smtps), set to `true` +- **Default:** `false` + + +### DEV_DSF_BPE_PROCESS_ENGINE_COREPOOLSIZE +- **Property:** dev.dsf.bpe.process.engine.corePoolSize +- **Required:** No +- **Description:** Process engine job executor core pool size +- **Default:** `4` + + +### DEV_DSF_BPE_PROCESS_ENGINE_MAXPOOLSIZE +- **Property:** dev.dsf.bpe.process.engine.maxPoolSize +- **Required:** No +- **Description:** Process engine job executor max pool size, additional threads until max pool size are created if the queue is full +- **Default:** `10` + + +### DEV_DSF_BPE_PROCESS_ENGINE_QUEUESIZE +- **Property:** dev.dsf.bpe.process.engine.queueSize +- **Required:** No +- **Description:** Process engine job executor queue size, jobs are added to the queue if all core pool threads are busy +- **Default:** `40` + + +### DEV_DSF_BPE_PROCESS_EXCLUDED +- **Property:** dev.dsf.bpe.process.excluded +- **Required:** No +- **Description:** List of process names that should be excluded from deployment during startup of the DSF BPE server; comma or space separated list, YAML block scalars supported +- **Recommendation:** Only deploy processes that can be started depending on your organization's roles in the Allow-List +- **Example:** `dsfdev_updateAllowList|1.0, another_process|x.y` + + +### DEV_DSF_BPE_PROCESS_FHIR_SERVER_RETRY_MAX +- **Property:** dev.dsf.bpe.process.fhir.server.retry.max +- **Required:** No +- **Description:** Number of retries until a connection can be established with the local DSF FHIR server during process deployment, `-1` means infinite number of retries +- **Default:** `-1` + + +### DEV_DSF_BPE_PROCESS_FHIR_SERVER_RETRY_SLEEP +- **Property:** dev.dsf.bpe.process.fhir.server.retry.sleep +- **Required:** No +- **Description:** Milliseconds between two retries to establish a connection with the local DSF FHIR server during process deployment +- **Default:** `5000` + + +### DEV_DSF_BPE_PROCESS_PLUGIN_DIRECTROY +- **Property:** dev.dsf.bpe.process.plugin.directroy +- **Required:** No +- **Description:** Directory containing the DSF BPE process plugins for deployment on startup of the DSF BPE server +- **Recommendation:** Change only if you don't use the provided directory structure from the installation guide or made changes to tit +- **Default:** `process` + + +### DEV_DSF_BPE_PROCESS_RETIRED +- **Property:** dev.dsf.bpe.process.retired +- **Required:** No +- **Description:** List of already deployed process names that should be retired during startup of the DSF BPE server; comma or space separated list, YAML block scalars supported +- **Recommendation:** Retire processes that where deployed previously but are not anymore available +- **Example:** `old_process|x.y` + + +### DEV_DSF_BPE_PROCESS_THREADS +- **Property:** dev.dsf.bpe.process.threads +- **Required:** No +- **Description:** Number of parallel Task / QuestionnaireResponse threads to start new or continue existing processes, a value `<= 0` means number of cpu cores +- **Default:** `-1` + + +### DEV_DSF_PROXY_NOPROXY +- **Property:** dev.dsf.proxy.noProxy +- **Required:** No +- **Description:** Forward proxy no-proxy list, entries will match exactly or agianst (one level) sub-domains, if no port is specified - all ports are matched; comma or space separated list, YAML block scalars supported +- **Example:** `foo.bar, test.com:8080` + + +### DEV_DSF_PROXY_PASSWORD or DEV_DSF_PROXY_PASSWORD_FILE +- **Property:** dev.dsf.proxy.password +- **Required:** No +- **Description:** Forward Proxy password +- **Recommendation:** Configure password if proxy requires authentication, use docker secret file to configure using *DEV_DSF_PROXY_PASSWORD_FILE* + + +### DEV_DSF_PROXY_URL +- **Property:** dev.dsf.proxy.url +- **Required:** No +- **Description:** Forward (http/https) proxy url, use *DEV_DSF_BPE_PROXY_NOPROXY* to list domains that do not require a forward proxy +- **Example:** `http://proxy.foo:8080` + + +### DEV_DSF_PROXY_USERNAME +- **Property:** dev.dsf.proxy.username +- **Required:** No +- **Description:** Forward proxy username +- **Recommendation:** Configure username if proxy requires authentication \ No newline at end of file diff --git a/docs/src/v1.4.0/maintain/fhir-reverse-proxy/README.md b/docs/src/v1.4.0/maintain/fhir-reverse-proxy/README.md new file mode 100644 index 000000000..d88afe12a --- /dev/null +++ b/docs/src/v1.4.0/maintain/fhir-reverse-proxy/README.md @@ -0,0 +1,6 @@ +--- +title: FHIR Reverse Proxy +icon: module +--- +## Overview +- [Configuration Parameters](configuration) diff --git a/docs/src/v1.4.0/maintain/fhir-reverse-proxy/configuration.md b/docs/src/v1.4.0/maintain/fhir-reverse-proxy/configuration.md new file mode 100644 index 000000000..dd1af657c --- /dev/null +++ b/docs/src/v1.4.0/maintain/fhir-reverse-proxy/configuration.md @@ -0,0 +1,87 @@ +--- +title: Configuration Parameters +icon: config +--- + +### APP_SERVER_IP +- **Required:** Yes +- **Description:** Hostname or IP-Address of the DSF FHIR servers application container, the reverse proxy target +- **Example:** `app`, `172.28.1.3` + + +### HTTPS_SERVER_NAME_PORT +- **Required:** Yes +- **Description:** External FQDN of your DSF FHIR server with port, typically `443` +- **Example:** `my-external.fqdn:443` + + +### PROXY_PASS_CONNECTION_TIMEOUT_HTTP +- **Required:** No +- **Description:** Connection timeout (seconds) for reverse proxy to app server http connection, time the proxy waits for a connection to be established +- **Default:** `30` seconds + + +### PROXY_PASS_CONNECTION_TIMEOUT_WS +- **Required:** No +- **Description:** Connection timeout (seconds) for reverse proxy to app server ws connection, time the proxy waits for a connection to be established +- **Default:** `30` seconds + + +### PROXY_PASS_TIMEOUT_HTTP +- **Required:** No +- **Description:** Timeout (seconds) for reverse proxy to app server http connection, time the proxy waits for a reply +- **Default:** `60` seconds + + +### PROXY_PASS_TIMEOUT_WS +- **Required:** No +- **Description:** Timeout (seconds) for reverse proxy to app server ws connection, time the proxy waits for a reply +- **Default:** `60` seconds + + +### SERVER_CONTEXT_PATH +- **Required:** No +- **Description:** Reverse proxy context path that delegates to the app server, `/` character at start, no `/` character at end, use `''` (empty string) to configure root as context path. +- **Default:** `/fhir` + + +### SSL_CA_CERTIFICATE_FILE +- **Required:** Yes +- **Description:** Certificate chain file including all signing, intermediate and ca certificate used to validate client certificates, PEM encoded, sets the apache httpd parameter `SSLCACertificateFile` +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/ssl_ca_certificate_file.pem` + + +### SSL_CA_DN_REQUEST_FILE +- **Required:** No +- **Description:** File containing all signing certificates excepted, will be used to specify the `Acceptable client certificate CA names` send to the client, during TLS handshake, sets the apache httpd parameter `SSLCADNRequestFile`; if omitted all entries from `SSL_CA_CERTIFICATE_FILE` are used +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/ssl_ca_dn_request_file.pem` + + +### SSL_CERTIFICATE_CHAIN_FILE +- **Required:** No +- **Description:** Certificate chain file, PEM encoded, must contain all certificates between the server certificate and the root ca certificate, sets the apache httpd parameter `SSLCertificateChainFile`; can be omitted if either no chain is needed (aka self signed server certificate) or the file specified via `SSL_CERTIFICATE_FILE` contains the certificate chain +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/ssl_certificate_chain_file.pem` + + +### SSL_CERTIFICATE_FILE +- **Required:** Yes +- **Description:** Server certificate file, PEM encoded, sets the apache httpd parameter `SSLCertificateFile` +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/ssl_certificate_file.pem` + + +### SSL_CERTIFICATE_KEY_FILE +- **Required:** Yes +- **Description:** Server certificate private key file, PEM encoded, unencrypted, sets the apache httpd parameter `SSLCertificateKeyFile` +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/ssl_certificate_key_file.pem` + + +### SSL_VERIFY_CLIENT +- **Required:** No +- **Description:** Modifies the apache mod_ssl config parameter `SSLVerifyClient` +- **Recommendation:** Set to `optional` when using OIDC authentication +- **Default:** `require` diff --git a/docs/src/v1.4.0/maintain/fhir/README.md b/docs/src/v1.4.0/maintain/fhir/README.md new file mode 100644 index 000000000..cedc99c38 --- /dev/null +++ b/docs/src/v1.4.0/maintain/fhir/README.md @@ -0,0 +1,8 @@ +--- +title: FHIR Server +icon: module +--- +## Overview +- [Configuration Parameters](configuration) +- [Access Control](access-control) +- [OpenID Connect](oidc) diff --git a/docs/src/v1.4.0/maintain/fhir/access-control.md b/docs/src/v1.4.0/maintain/fhir/access-control.md new file mode 100644 index 000000000..7c87423a8 --- /dev/null +++ b/docs/src/v1.4.0/maintain/fhir/access-control.md @@ -0,0 +1,129 @@ +--- +title: Access Control +icon: config +--- + +## Overview + +The DSF FHIR server implements a subset of the FHIR R4 [REST API](http://hl7.org/fhir/R4/http.html). When accessing the API with a web browser a limited graphical user interface is shown. Without any additional configuration the API and user interface is only accessible with the X.509 client certificate configured for the organization via the configuration parameter: [DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT](configuration#dev-dsf-fhir-server-organization-thumbprint) + +::: tip OpenID Connect +To enable OpenID Connect authentication of local user, see the DSF FHIR server OpenID Connect [configuration page](oidc). +::: + +Access to the API and user interface can be enabled for additional client certificates and local users authenticating via OAuth 2.0 OpenID Connect. Access can be configured for so called roles, with all roles specified using the configuration parameter [DEV_DSF_FHIR_SERVER_ROLECONFIG](configuration#dev-dsf-fhir-server-roleconfig). The value for this environment variable is specified as YAML using the block scalar `|`. + +The listing below shows a minimal configuration to enable read access for a specific client-certificate: + +```yaml + DEV_DSF_FHIR_SERVER_ROLECONFIG: | + - example_read_only_role: + thumbprint: 00474993fa261b0225f93c5a66aa6fcc... [a-f0-9]{128} + dsf-role: + - READ + - SEARCH + - HISTORY +``` +The list of user roles above contains a single entry `example_read_only_role`, matching the user via a client certificate SHA-512 thumprint and assigning three DSF roles. + +::: tip Certificate Thumbprints +SHA-512 certificate thumbprints in HEX form `[a-f0-9]{128}` can be calculated using: +```sh +certtool --fingerprint --hash=sha512 --infile=certificate.pem +``` +::: + +Multiple user roles can be specified and all matching roles will be applied to an authenticated users. Use an empty string `""` or a single block scalar `|` character as the value for the configuration parameter [DEV_DSF_FHIR_SERVER_ROLECONFIG](configuration#dev-dsf-fhir-server-roleconfig) if no roles should be configured. + +## Matching Users + +To apply roles, users can be matched via the `thumbprint`, `email`, `token-role` or `token-group` properties. A single value or a list of values can be specified. + +#### thumbprint + +The property `thumbprint` can used to specify one or multiple SHA-512 certificate thumbprints. Roles from this rule are applied to the authenticating user if the certificate matches one of the specified thumbprints. + +#### email + +Using the property `email` users can be matched against e-mail addresses specified in X.509 client certificates and in OpenID Connect access tokens. Values will be matched against e-mail addresses specified in the subject DN (via PKCS#9 extension 1.2.840.113549.1.9.1) and RFC-822 Name entries of the Subject Alternative Name field. If the user authenticates via OpenID Connect, the `email` [claim](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) from the access token will be matched against the property values. + +#### token-role and token-group + +With the properties `token-role` and `token-group` role and group names can be specified to match against role and group claims within OAuth 2.0 access tokens. + + +## DSF and Practitioner Roles + +To types of roles can be applied to matched users. + +#### dsf-role + +DSF roles specified via the `dsf-role` property define general access to the REST API and user interface. Allowed values are: + +`CREATE`, `READ`, `UPDATE`, `DELETE`, `SEARCH`, `HISTORY`, `PERMANENT_DELETE` and `WEBSOCKET`. + +#### practitioner-role + +In order to allow users to start processes, the property `practitioner-role` can be used to assign codes from FHIR [CodeSystem](http://hl7.org/fhir/R4/codesystem.html) resources. Codes are specified in the form `system-url|code`. +If the uses has a code specified here that match with a `requester` extension within the process plugin's [ActivityDefinition](http://hl7.org/fhir/R4/activitydefinition.html) resource, the user can start the process if he also has the `dsf-role` `CREATE`. + +Process plugins can defined and use there own code-systems. However, the DSF specifies a standard set of practitioner roles within the CodeSystem `http://dsf.dev/fhir/CodeSystem/practitioner-role`: + +`UAC_USER`, `COS_USER`, `CRR_USER`, `DIC_USER`, `DMS_USER`, `DTS_USER`, `HRP_USER`, `TTP_USER`, `AMS_USER` and `DSF_ADMIN`. + + +## Examples + +The first example defines a group of DSF administrators. Two client certificates match against this role: + +```yaml + DEV_DSF_FHIR_SERVER_ROLECONFIG: | + - certificate-admins: + thumbprint: + - afb68b1d9d47e691b8b3d50fd9848467cada8b1c76f5f4b45f00c9f8432d505361a3ee27805f4aa06799d9ac8dace94b3f1942fce44d84866961259b13be825d + - 2441bfddcad97eeb83c8c31fe181b90652787b8b59bf4e569219da7db4429e389479cb7c4a2f311e34217357d594ecad7d58ccfeef2a9e93c6fcf8d98897d88c + dsf-role: + - CREATE + - READ + - UPDATE + - DELETE + - SEARCH + - HISTORY + practitioner-role: + - http://dsf.dev/fhir/CodeSystem/practitioner-role|DSF_ADMIN + +``` + + +The second example defines a group of DSF administrators by specifying an `admin` role that gets matched against OAuth 2.0 access tokens: + +```yaml + DEV_DSF_FHIR_SERVER_ROLECONFIG: | + - token-role-admins: + token-role: admin + dsf-role: + - CREATE + - READ + - UPDATE + - DELETE + - SEARCH + - HISTORY + practitioner-role: + - http://dsf.dev/fhir/CodeSystem/practitioner-role|DSF_ADMIN + +``` + + +The third example allows read-only access. Two e-mail addresses are used to match this role. E-mail addresses from X.509 client certificates and OAuth 2.0 access tokens are matched: + +```yaml + DEV_DSF_FHIR_SERVER_ROLECONFIG: | + - read-only: + email: + - first.user@test.org + - second.user@test.org + dsf-role: + - READ + - SEARCH + - HISTORY +``` diff --git a/docs/src/v1.4.0/maintain/fhir/configuration.md b/docs/src/v1.4.0/maintain/fhir/configuration.md new file mode 100644 index 000000000..f41874328 --- /dev/null +++ b/docs/src/v1.4.0/maintain/fhir/configuration.md @@ -0,0 +1,392 @@ +--- +title: Configuration Parameters +icon: config +--- + +### DEV_DSF_FHIR_CLIENT_CERTIFICATE +- **Property:** dev.dsf.fhir.client.certificate +- **Required:** Yes +- **Description:** PEM encoded file with local client certificate for https connections to remote DSF FHIR servers +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/app_client_certificate.pem` + + +### DEV_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY +- **Property:** dev.dsf.fhir.client.certificate.private.key +- **Required:** Yes +- **Description:** Private key corresponding to the local client certificate as PEM encoded file. Use *DEV_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD* or *DEV_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE* if private key is encrypted +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/app_client_certificate_private_key.pem` + + +### DEV_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD or DEV_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE +- **Property:** dev.dsf.fhir.client.certificate.private.key.password +- **Required:** No +- **Description:** Password to decrypt the local client certificate encrypted private key +- **Recommendation:** Use docker secret file to configure using *DEV_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE* +- **Example:** `/run/secrets/app_client_certificate_private_key.pem.password` + + +### DEV_DSF_FHIR_CLIENT_TIMEOUT_CONNECT +- **Property:** dev.dsf.fhir.client.timeout.connect +- **Required:** No +- **Description:** The timeout in milliseconds until a connection is established between this DSF FHIR server and a remote DSF FHIR server +- **Recommendation:** Change default value only if timeout exceptions occur +- **Default:** `2000` + + +### DEV_DSF_FHIR_CLIENT_TIMEOUT_READ +- **Property:** dev.dsf.fhir.client.timeout.read +- **Required:** No +- **Description:** The timeout in milliseconds until a reading a resource from a remote DSF FHIR server is aborted +- **Recommendation:** Change default value only if timeout exceptions occur +- **Default:** `10000` + + +### DEV_DSF_FHIR_CLIENT_TRUST_SERVER_CERTIFICATE_CAS +- **Property:** dev.dsf.fhir.client.trust.server.certificate.cas +- **Required:** Yes +- **Description:** PEM encoded file with one or more trusted root certificates to validate server certificates for https connections to remote DSF FHIR servers +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/app_client _trust_certificates.pem` + + +### DEV_DSF_FHIR_CLIENT_VERBOSE +- **Property:** dev.dsf.fhir.client.verbose +- **Required:** No +- **Description:** To enable verbose logging of requests to and replies from remote DSF FHIR servers, set to `true` +- **Default:** `false` + + +### DEV_DSF_FHIR_DB_LIQUIBASE_FORCEUNLOCK +- **Property:** dev.dsf.fhir.db.liquibase.forceUnlock +- **Required:** No +- **Description:** To force liquibase to unlock the migration lock set to `true` +- **Recommendation:** Only use this option temporarily to unlock a stuck DB migration step +- **Default:** `false` + + +### DEV_DSF_FHIR_DB_LIQUIBASE_LOCKWAITTIME +- **Property:** dev.dsf.fhir.db.liquibase.lockWaitTime +- **Required:** No +- **Description:** Liquibase change lock wait time in minutes, default 2 minutes +- **Default:** `2` + + +### DEV_DSF_FHIR_DB_LIQUIBASE_PASSWORD or DEV_DSF_FHIR_DB_LIQUIBASE_PASSWORD_FILE +- **Property:** dev.dsf.fhir.db.liquibase.password +- **Required:** Yes +- **Description:** The password to access the database from the DSF FHIR server to execute database migrations +- **Recommendation:** Use docker secret file to configure by using *DEV_DSF_FHIR_DB_LIQUIBASE_PASSWORD_FILE* +- **Example:** `/run/secrets/db_liquibase.password` + + +### DEV_DSF_FHIR_DB_LIQUIBASE_USERNAME +- **Property:** dev.dsf.fhir.db.liquibase.username +- **Required:** No +- **Description:** The user name to access the database from the DSF FHIR server to execute database migrations +- **Default:** `liquibase_user` + + +### DEV_DSF_FHIR_DB_URL +- **Property:** dev.dsf.fhir.db.url +- **Required:** Yes +- **Description:** The address of the database used for the DSF FHIR server +- **Recommendation:** Change only if you don't use the provided docker-compose from the installation guide or made changes to the database settings/networking in the docker-compose +- **Example:** `jdbc:postgresql://db/fhir` + + +### DEV_DSF_FHIR_DB_USER_GROUP +- **Property:** dev.dsf.fhir.db.user.group +- **Required:** No +- **Description:** The name of the user group to access the database from the DSF FHIR server +- **Default:** `fhir_users` + + +### DEV_DSF_FHIR_DB_USER_PASSWORD or DEV_DSF_FHIR_DB_USER_PASSWORD_FILE +- **Property:** dev.dsf.fhir.db.user.password +- **Required:** Yes +- **Description:** The password to access the database from the DSF FHIR server +- **Recommendation:** Use docker secret file to configure using *DEV_DSF_FHIR_DB_USER_PASSWORD_FILE* +- **Example:** `/run/secrets/db_user.password` + + +### DEV_DSF_FHIR_DB_USER_PERMANENT_DELETE_GROUP +- **Property:** dev.dsf.fhir.db.user.permanent.delete.group +- **Required:** No +- **Description:** The name of the user group to access the database from the DSF FHIR server for permanent deletes +- **Default:** `fhir_permanent_delete_users` + + +### DEV_DSF_FHIR_DB_USER_PERMANENT_DELETE_PASSWORD or DEV_DSF_FHIR_DB_USER_PERMANENT_DELETE_PASSWORD_FILE +- **Property:** dev.dsf.fhir.db.user.permanent.delete.password +- **Required:** Yes +- **Description:** The password to access the database from the DSF FHIR server for permanent deletes +- **Recommendation:** Use docker secret file to configure using *DEV_DSF_FHIR_DB_USER_PERMANENT_DELETE_PASSWORD_FILE* +- **Example:** `/run/secrets/db_user_permanent_delete.password` + + +### DEV_DSF_FHIR_DB_USER_PERMANENT_DELETE_USERNAME +- **Property:** dev.dsf.fhir.db.user.permanent.delete.username +- **Required:** No +- **Description:** The user name to access the database from the DSF FHIR server for permanent deletes +- **Recommendation:** Use a different user then *DEV_DSF_FHIR_DB_USER_USERNAME* +- **Default:** `fhir_server_permanent_delete_user` + + +### DEV_DSF_FHIR_DB_USER_USERNAME +- **Property:** dev.dsf.fhir.db.user.username +- **Required:** No +- **Description:** The user name to access the database from the DSF FHIR server +- **Default:** `fhir_server_user` + + +### DEV_DSF_FHIR_SERVER_BASE_URL +- **Property:** dev.dsf.fhir.server.base.url +- **Required:** Yes +- **Description:** The base address of this DSF FHIR server to read/store fhir resources +- **Example:** `https://foo.bar/fhir` + + +### DEV_DSF_FHIR_SERVER_INIT_BUNDLE +- **Property:** dev.dsf.fhir.server.init.bundle +- **Required:** No +- **Description:** The fhir bundle containing the initial Allow-List, loaded on startup of the DSF FHIR server +- **Recommendation:** Change only if you don't use the provided files from the installation guide, have local changes in the Allow-List or received an Allow-List from another source +- **Default:** `conf/bundle.xml` + + +### DEV_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE +- **Property:** dev.dsf.fhir.server.organization.identifier.value +- **Required:** Yes +- **Description:** The local identifier value used in the Allow-List +- **Recommendation:** By convention: The shortest possible FQDN that resolve the homepage of the organization +- **Example:** `hospital.com` + + +### DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT +- **Property:** dev.dsf.fhir.server.organization.thumbprint +- **Required:** Yes +- **Description:** The SHA-512 thumbprint of the local organization client certificate +- **Recommendation:** The thumbprint can be calculated via `certtool --fingerprint --hash=sha512 --infile=client_certificate.pem` + + +### DEV_DSF_FHIR_SERVER_PAGE_COUNT +- **Property:** dev.dsf.fhir.server.page.count +- **Required:** No +- **Description:** The page size returned by the DSF FHIR server when reading/searching fhir resources +- **Default:** `20` + + +### DEV_DSF_FHIR_SERVER_ROLECONFIG +- **Property:** dev.dsf.fhir.server.roleConfig +- **Required:** No +- **Description:** Role config YAML as defined in [FHIR Server: Access Control](access-control). + + +### DEV_DSF_FHIR_SERVER_STATIC_RESOURCE_CACHE +- **Property:** dev.dsf.fhir.server.static.resource.cache +- **Required:** No +- **Description:** To disable static resource caching, set to `false` +- **Recommendation:** Only set to `false` for development +- **Default:** `true` + + +### DEV_DSF_PROXY_NOPROXY +- **Property:** dev.dsf.proxy.noProxy +- **Required:** No +- **Description:** Forward proxy no-proxy list, entries will match exactly or agianst (one level) sub-domains, if no port is specified - all ports are matched; comma or space separated list, YAML block scalars supported +- **Example:** `foo.bar, test.com:8080` + + +### DEV_DSF_PROXY_PASSWORD or DEV_DSF_PROXY_PASSWORD_FILE +- **Property:** dev.dsf.proxy.password +- **Required:** No +- **Description:** Forward Proxy password +- **Recommendation:** Configure password if proxy requires authentication, use docker secret file to configure using *DEV_DSF_PROXY_PASSWORD_FILE* + + +### DEV_DSF_PROXY_URL +- **Property:** dev.dsf.proxy.url +- **Required:** No +- **Description:** Forward (http/https) proxy url, use *DEV_DSF_BPE_PROXY_NOPROXY* to list domains that do not require a forward proxy +- **Example:** `http://proxy.foo:8080` + + +### DEV_DSF_PROXY_USERNAME +- **Property:** dev.dsf.proxy.username +- **Required:** No +- **Description:** Forward proxy username +- **Recommendation:** Configure username if proxy requires authentication + + +### DEV_DSF_SERVER_API_HOST +- **Property:** dev.dsf.server.api.host +- **Required:** Yes +- **Description:** API connector host, default in docker image: `0.0.0.0` +- **Default:** `127.0.0.1` + + +### DEV_DSF_SERVER_API_PORT +- **Property:** dev.dsf.server.api.port +- **Required:** Yes +- **Description:** API connector port, default in docker image: `8080` + + +### DEV_DSF_SERVER_AUTH_CLIENT_CERTIFICATE_HEADER +- **Property:** dev.dsf.server.auth.client.certificate.header +- **Required:** Yes +- **Description:** Name of HTTP header with client certificate from reverse proxy +- **Default:** `X-ClientCert` + + +### DEV_DSF_SERVER_AUTH_OIDC_AUTHORIZATION_CODE_FLOW +- **Property:** dev.dsf.server.auth.oidc.authorization.code.flow +- **Required:** No +- **Description:** Set to `true` to enable OIDC authorization code flow +- **Recommendation:** Requires *DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_REALM_BASE_URL*, *DEV_DSF_SERVER_AUTH_OIDC_CLIENT_ID* and *DEV_DSF_SERVER_AUTH_OIDC_CLIENT_SECRET* to be specified +- **Default:** `false` + + +### DEV_DSF_SERVER_AUTH_OIDC_BACK_CHANNEL_LOGOUT +- **Property:** dev.dsf.server.auth.oidc.back.channel.logout +- **Required:** No +- **Description:** Set to `true` to enable OIDC back-channel logout +- **Recommendation:** Requires *DEV_DSF_SERVER_AUTH_OIDC_AUTHORIZATION_CODE_FLOW* to be set to `true` (enabled), *DEV_DSF_SERVER_AUTH_OIDC_CLIENT_ID* and *DEV_DSF_SERVER_AUTH_OIDC_BACK_CHANNEL_LOGOUT_PATH* to be specified +- **Default:** `false` + + +### DEV_DSF_SERVER_AUTH_OIDC_BACK_CHANNEL_LOGOUT_PATH +- **Property:** dev.dsf.server.auth.oidc.back.channel.logout.path +- **Required:** No +- **Description:** Path called by the OIDC provide to request back-channel logout +- **Default:** `/back-channel-logout` + + +### DEV_DSF_SERVER_AUTH_OIDC_BEARER_TOKEN +- **Property:** dev.dsf.server.auth.oidc.bearer.token +- **Required:** No +- **Description:** Set to `true` to enable OIDC bearer token authentication +- **Recommendation:** Requires *DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_REALM_BASE_URL* to be specified +- **Default:** `false` + + +### DEV_DSF_SERVER_AUTH_OIDC_CLIENT_ID +- **Property:** dev.dsf.server.auth.oidc.client.id +- **Required:** No +- **Description:** OIDC provider client_id, must be specified if *DEV_DSF_SERVER_AUTH_OIDC_AUTHORIZATION_CODE_FLOW* is enabled + + +### DEV_DSF_SERVER_AUTH_OIDC_CLIENT_SECRET +- **Property:** dev.dsf.server.auth.oidc.client.secret +- **Required:** No +- **Description:** OIDC provider client_secret, must be specified if *DEV_DSF_SERVER_AUTH_OIDC_AUTHORIZATION_CODE_FLOW* is enabled + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE +- **Property:** dev.dsf.server.auth.oidc.provider.client.certificate +- **Required:** No +- **Description:** PEM encoded file with client certificate for https connections to the OIDC provider +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/oidc_provider_client_certificate.pem` + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE_PRIVATE_KEY +- **Property:** dev.dsf.server.auth.oidc.provider.client.certificate.private.key +- **Required:** No +- **Description:** Private key corresponding to the client certificate for the OIDC provider as PEM encoded file. Use *DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD* or *DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE* if private key is encrypted +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/oidc_provider_client_certificate_private_key.pem` + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD or DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE +- **Property:** dev.dsf.server.auth.oidc.provider.client.certificate.private.key.password +- **Required:** No +- **Description:** Password to decrypt the client certificate for the OIDC provider encrypted private key +- **Recommendation:** Use docker secret file to configure using *DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE* +- **Example:** `/run/secrets/oidc_provider_client_certificate_private_key.pem.password` + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_CONNECTTIMEOUT +- **Property:** dev.dsf.server.auth.oidc.provider.client.connectTimeout +- **Required:** No +- **Description:** OIDC provider client connect timeout in milliseconds +- **Default:** `5000` + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_IDLETIMEOUT +- **Property:** dev.dsf.server.auth.oidc.provider.client.idleTimeout +- **Required:** No +- **Description:** OIDC provider client idle timeout in milliseconds +- **Default:** `30000` + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_TRUST_SERVER_CERTIFICATE_CAS +- **Property:** dev.dsf.server.auth.oidc.provider.client.trust.server.certificate.cas +- **Required:** No +- **Description:** PEM encoded file with one or more trusted root certificates to validate server certificates for https connections to the OIDC provider +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/oidc_provider_trust_certificates.pem` + + +### DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_REALM_BASE_URL +- **Property:** dev.dsf.server.auth.oidc.provider.realm.base.url +- **Required:** No +- **Description:** OIDC provider realm base url +- **Example:** `https://keycloak.test.com:8443/realms/example-realm-name` + + +### DEV_DSF_SERVER_AUTH_TRUST_CLIENT_CERTIFICATE_CAS +- **Property:** dev.dsf.server.auth.trust.client.certificate.cas +- **Required:** Yes +- **Description:** PEM encoded file with one or more trusted root certificates to validate client certificates for https connections from local and remote clients +- **Recommendation:** Use docker secret file to configure +- **Example:** `/run/secrets/app_client_trust_certificates.pem` + + +### DEV_DSF_SERVER_CERTIFICATE +- **Property:** dev.dsf.server.certificate +- **Required:** No +- **Description:** Server certificate file for testing +- **Recommendation:** Only specify For testing when terminating TLS in jetty server + + +### DEV_DSF_SERVER_CERTIFICATE_CHAIN +- **Property:** dev.dsf.server.certificate.chain +- **Required:** No +- **Description:** Server certificate chain file for testing +- **Recommendation:** Only specify For testing when terminating TLS in jetty server + + +### DEV_DSF_SERVER_CERTIFICATE_KEY +- **Property:** dev.dsf.server.certificate.key +- **Required:** No +- **Description:** Server certificate private key file for testing +- **Recommendation:** Only specify For testing when terminating TLS in jetty server + + +### DEV_DSF_SERVER_CERTIFICATE_KEY_PASSWORD or DEV_DSF_SERVER_CERTIFICATE_KEY_PASSWORD_FILE +- **Property:** dev.dsf.server.certificate.key.password +- **Required:** No +- **Description:** Server certificate private key file password for testing +- **Recommendation:** Only specify For testing when terminating TLS in jetty server + + +### DEV_DSF_SERVER_CONTEXT_PATH +- **Property:** dev.dsf.server.context.path +- **Required:** Yes +- **Description:** Web application context path, default in `bpe` docker image: `/bpe`, default in `fhir` docker image: `/fhir` +- **Recommendation:** Only modify for testing + + +### DEV_DSF_SERVER_STATUS_HOST +- **Property:** dev.dsf.server.status.host +- **Required:** Yes +- **Description:** Status connector host +- **Default:** `127.0.0.1` + + +### DEV_DSF_SERVER_STATUS_PORT +- **Property:** dev.dsf.server.status.port +- **Required:** Yes +- **Description:** Status connector port, default in docker image: `10000` \ No newline at end of file diff --git a/docs/src/v1.4.0/maintain/fhir/oidc.md b/docs/src/v1.4.0/maintain/fhir/oidc.md new file mode 100644 index 000000000..7b12b39d8 --- /dev/null +++ b/docs/src/v1.4.0/maintain/fhir/oidc.md @@ -0,0 +1,63 @@ +--- +title: OpenID Connect +icon: config +--- + +## Overview +Access to the DSF FHIR server REST API and user interface can be configured via [access control roles](access-control). By default users are authenticated using X.509 client certificates, but authentication for local users via OAuth 2.0 OpenID Connect can also be enabled. + +The DSF FHIR server supports [Authorization Code Flow](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth) for the user interface as well as [Bearer Token Authentication](https://datatracker.ietf.org/doc/html/rfc6750) for the REST API. [Back-Channel Logout](https://openid.net/specs/openid-connect-backchannel-1_0.html) is also supported. + + +::: tip FHIR Reverse Proxy +The DSF FHIR reverse proxy requires client certificates by default. To use OpenID Connect authentication the configuration parameter [SSL_VERIFY_CLIENT](configuration/reverseproxy.html#ssl-verify-client) needs to be set to `optional`. +::: + + +## Authorization Code Flow + +To enable authentication via OpenID Connect authorization code flow, set the configuration parameter [DEV_DSF_SERVER_AUTH_OIDC_AUTHORIZATION_CODE_FLOW](configuration#dev-dsf-server-auth-oidc-authorization-code-flow) to `true` and specify the following parameters: + +- [DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_REALM_BASE_URL](configuration#dev-dsf-server-auth-oidc-provider-realm-base-url) +- [DEV_DSF_SERVER_AUTH_OIDC_CLIENT_ID](configuration#dev-dsf-server-auth-oidc-client-id) +- [DEV_DSF_SERVER_AUTH_OIDC_CLIENT_SECRET](configuration#dev-dsf-server-auth-oidc-client-secret) + +Optionally, back channel logout can be enabled by setting [DEV_DSF_SERVER_AUTH_OIDC_BACK_CHANNEL_LOGOUT](configuration#dev-dsf-server-auth-oidc-back-channel-logout) to `true`. The DSF FHIR server accepts logout tokens at [DEV_DSF_FHIR_SERVER_BASE_URL](configuration#dev-dsf-fhir-server-base-url) + `/back-channel-logout`. The path can be modified via [DEV_DSF_SERVER_AUTH_OIDC_BACK_CHANNEL_LOGOUT_PATH](configuration#dev-dsf-server-auth-oidc-back-channel-logout-path). + + +## Bearer Token Authentication + +To enable bearer token authentication, set the configuration parameter [DEV_DSF_SERVER_AUTH_OIDC_BEARER_TOKEN](configuration#dev-dsf-server-auth-oidc-bearer-token) to `true` and specify the following parameter: +- [DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_REALM_BASE_URL](configuration#dev-dsf-server-auth-oidc-provider-realm-base-url) + + +## Additional ODIC Configuration Parameter + +A number of additional `DEV_DSF_SERVER_AUTH_OIDC ...` configuration parameter are specify on the DSF FHIR server [configuration parameter page](configuration). + +For example the configuration parameter [DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_TRUST_SERVER_CERTIFICATE_CAS](configuration#dev-dsf-server-auth-oidc-provider-client-trust-server-certificate-cas) can be used to specify a PEM encoded file with trusted root certificates to be used when accessing the OpenID Connect provider. If not specify the JVM default trusted root certificates are used for this connection. + + +## Example +```yaml +services: + app: + image: ghcr.io/datasharingframework/fhir:1.1.0 + # ... + secrets: + - keycloak_root_ca.pem + # ... + environment: + # ... + DEV_DSF_SERVER_AUTH_OIDC_AUTHORIZATION_CODE_FLOW: 'true' + DEV_DSF_SERVER_AUTH_OIDC_BACK_CHANNEL_LOGOUT: 'true' + DEV_DSF_SERVER_AUTH_OIDC_BEARER_TOKEN: 'true' + DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_REALM_BASE_URL: https://keycloak.test.org/realms/dsf + DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_TRUST_SERVER_CERTIFICATE_CAS: /run/secrets/keycloak_root_ca.pem + DEV_DSF_SERVER_AUTH_OIDC_CLIENT_ID: dsf-fhir + DEV_DSF_SERVER_AUTH_OIDC_CLIENT_SECRET: n9bCMtjugv3Y_.szktXyQ2RH5se+J%o3 + # ... +secrets: + keycloak_root_ca.pem: + file: ./secrets/keycloak_root_ca.pem +``` \ No newline at end of file diff --git a/docs/src/v1.4.0/maintain/install-plugins.md b/docs/src/v1.4.0/maintain/install-plugins.md new file mode 100644 index 000000000..17774ffe0 --- /dev/null +++ b/docs/src/v1.4.0/maintain/install-plugins.md @@ -0,0 +1,21 @@ +--- +title: Install Plugins +icon: plugin +--- + +You can find an overview of compatable process plugins below. + +## Common processes + +- Ping-Pong: https://github.com/datasharingframework/dsf-process-ping-pong/releases +- AllowList Download: https://github.com/datasharingframework/dsf-process-allow-list/releases + +## MII processes + +- Feasibility: https://github.com/medizininformatik-initiative/feasibility-dsf-process/releases +- KDS-Report: https://github.com/medizininformatik-initiative/mii-process-report/releases + +- MII-Data-Transfer: https://github.com/medizininformatik-initiative/mii-process-data-transfer/releases + +## NUM processes +- NUM-RDP: https://github.com/num-codex/codex-processes-ap1/releases diff --git a/docs/src/v1.4.0/maintain/install.md b/docs/src/v1.4.0/maintain/install.md new file mode 100644 index 000000000..e67a8ba50 --- /dev/null +++ b/docs/src/v1.4.0/maintain/install.md @@ -0,0 +1,232 @@ +--- +title: Install DSF 1.4.0 +icon: install +--- + +In the following installation manual we will show you how you can install your own DSF instance to be part of an already existing DSF network. + +::: tip Unified installation manual + +The installation instructions of DSF 0.9.x for different application use cases (e.g. NUM CODEX or HiGHmed) are now combined under one common manual. The specific steps for process installation and configuration are documented at the process plugin documentation pages. +::: + +## Prerequisites +### Virtual Machines +* DSF FHIR VM: min. 4 GB RAM, 4 vCPU, 20 GB HDD +* DSF BPE VM: min. 4 GB RAM, 4 vCPU, 20 GB HDD +### Docker / Docker-Compose +Both VMs need latest docker (>= 24.0.0) and docker compose. For the latest install guide see https://docs.docker.com/engine/install. + +``` +sudo apt-get update +sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg +echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +sudo apt-get update +sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin +sudo systemctl enable docker.service +sudo systemctl enable containerd.service +``` + +The current version of docker compose is installed with the current docker version. + +### Client/Server Certificates +Two Certificates from the GÉANT TCS (via DFN e.V.), D-Trust (via TMF e.V.) or DFN-PKI Global G2 (legacy, no new certificates are issued) are needed: +* Certificate _A_: Server Certificate - `TLS Web Server Authentication` (DFN PKI Profile: 'Web Server', Common-Name: Your external DSF FHIR Servers FQDN) +* Certificate _B_: Client Certificate - `TLS Web Client Authentication` (DFN PKI Profile: '802.1X Client', Common-Name: Your DSF BPE Servers FQDN) + +If you use GÉANT TCS certificates, then they are configured by default with the necessary *X509v3 Extended Key Usage*s: `TLS Web Server Authentication, TLS Web Client Authentication`. + + +### Network setup / Network access + +* The DSF FHIR server needs to be accessible via the internet and able to access the internet without TLS interception. +* The BPE FHIR server should only be accessible by the internal network and able to access your DSF FHIR server via its external FQDN and the internet without TLS interception. + +Here is a quick overview of the expected network setup. + +| Source | Target | Port | Protocol | +| ----------------------------- | ----------------------------- | ---- | ---------------------- | +| DSF BPE (local) | DSF FHIR (local) | 443 | https, wss | +| DSF BPE (local) | DSF FHIR (other DSF communication partners) | 443 | https | +| DSF FHIR (local) | DSF FHIR (other DSF communication partners) | 443 | https (HTTP HEAD only) | +| DSF BPE (other DSF communication partners) | DSF FHIR (local) | 443 | https | +| DSF FHIR (other DSF communication partners) | DSF FHIR (local) | 443 | https (HTTP HEAD only) | + + Connections to services that are used by process plugins (e.g. a fTTP, a terminology server, simplifier.net or a local FHIR server) are not listed. Please refer to the respective process plugin documentation pages for more information. + + + +## Setup +### Prepare Certificates +1. Server Certificate (certificate _A_) + _This certificate will be used as the DSF FHIR servers server certificate (ssl_certificate_file.pem, ssl_certificate_key_file.pem)_ + * Store PEM encoded certificate as `ssl_certificate_file.pem` + * Store unencrypted, PEM encoded private-key as `ssl_certificate_key_file.pem` + +1. Client Certificate (Certificate _B_) + _This certificate will be used as the DSF BPE servers client certificate (client_certificate.pem, client_certificate_private_key.pem) as well as the DSF FHIR servers client certificate (client_certificate.pem, client_certificate_private_key.pem)_ + * Store PEM encoded certificate as `client_certificate.pem` + * Store encrypted or not encrypted, PEM encoded private-key as `client_certificate_private_key.pem` + +### DSF FHIR Server +1. Add Group/User + Add group and user used by the DSF FHIR java application. Ubuntu compatible commands below: + ``` + sudo groupadd --gid 2101 fhir + sudo useradd --system --no-create-home --uid 2101 --gid 2101 fhir + ``` + +1. Download and Extract Config Files + Download and unpack the prepared DSF FHIR server config files and folder structure: + ``` + cd /opt + wget https://dsf.dev/download/dsf_fhir_1_4_0.tar.gz + sudo tar --same-owner -zxvf dsf_fhir_1_4_0.tar.gz + ``` + _The `tar` command will unpack the config files at `/opt/fhir` assuming you changed into the `/opt` directory._ + +1. Verify that the `fhir` system user or group can write into the following folder + * `/opt/fhir/log` + +1. Add certificates and keys + * Add the server certificate (certificate _A_) and the corresponding private-key to **/opt/fhir/secrets/** + * ssl_certificate_file.pem (chmod: 440, chown: fhir:docker) + * ssl_certificate_key_file.pem (chmod: 440, chown: fhir:docker) + * Add the client certificate (Certificate _B_) and the corresponding private-key to **/opt/fhir/secrets/** + * client_certificate.pem (chmod: 440, chown: fhir:docker) + * client_certificate_private_key.pem (chmod: 440, chown: fhir:docker) + * If the private key is encrypted, add a password file with the password as the only content to **/opt/fhir/secrets/client_certificate_private_key.pem.password** + * If the private key is not encrypted, remove the corresponding docker secret lines from the `docker-compose.yml` file + ``` + L39: - app_client_certificate_private_key.pem.password + ... + L54: DEV_DSF_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE: /run/secrets/app_client_certificate_private_key.pem.password + ... + L141: app_client_certificate_private_key.pem.password: + L142: file: ./secrets/client_certificate_private_key.pem.password + ``` + + ::: tip How to chmod / chown + For the example *ssl_certificate_file.pem (chmod: 440, chown: fhir:docker)* you must: + + 1. Set the file content as requested + 2. Change the file permissions to 440 (allow read access to the owner of the file and the group the file belongs to, deny write access to everybody and deny read for other users): + `chmod 440 /opt/fhir/secrets/ssl_certificate_file.pem` + 3. Change the owner of the file to the user `fhir` and the group the file belongs to to `docker`: + `chown fhir:docker /opt/fhir/secrets/ssl_certificate_file.pem` + + ::: + +1. Uncomment one of the certificate chain entries in the docker-compose file base on the certificate authority that signed your DSF FHIR server certificate (certificate A). For example use the following two lines if the server certificate is signed by `DFN-Verein Global Issuing CA` + ``` + L114: ssl_certificate_chain_file.pem: + L115: file: ./secrets/ssl_certificate_chain_file_DFN-Verein.pem + ``` + +1. Modify database passwords + * **/opt/fhir/secrets/db_liquibase.password** + * Generate a random password (min. 32 characters recommended) and replace the content of the file. + * **/opt/fhir/secrets/db_user.password** + * Generate a random password (min. 16 characters recommended) and replace the content of the file. + * **/opt/fhir/secrets/db_user_permanent_delete.password** + * Generate a random password (min. 16 characters recommended) and replace the content of the file. + +1. Modify the docker-compose.yml file and set environment variables to the appropriate values + * **services -> proxy -> environment:** + * **HTTPS_SERVER_NAME_PORT**: _TODO_DSF_FHIR_SERVER_EXTERNAL_FQDN:443_ + Set your FHIR servers external FQDN, e.g. `foo.bar.de` -> `foo.bar.de:443` + * For additional environment variables, see [DSF configuration parameters - FHIR Reverse Proxy](fhir-reverse-proxy/configuration) + * **services -> app -> environment:** + * **DEV_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE**: `todo.organization.com` + Set your Organizations DSF identifier, aka the shortest FQDN that resolves to the main homepage of the organization, e.g. `hs-heilbronn.de` + * **DEV_DSF_FHIR_SERVER_BASE_URL**: `https://dsf.todo.organization.com/fhir` + Set your FHIR servers external FQDN, e.g. `foo.bar.de` -> `https://foo.bar.de/fhir` + * **DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT**: `f4344032fe77bffb912ff5abfd44da89fe64d355affb8d0f14c9ecb8bdbf92c7fe5f995b1ec0c453e4228b395e331052e4639044df4933d57721de508a84d26f` + Set the SHA-512 Hash (lowercase hex) of your client certificate (Certificate _B_) + Use `certtool --fingerprint --hash=sha512 --infile=client_certificate.pem` to generate the hash. + * **DEV_DSF_FHIR_SERVER_ROLECONFIG**: `|` + (Optional) You can add other client certificates (e.g. personal certificates from admins) to your DSF instance. For additional information, see the FHIR server [Access Control](fhir/access-control) page. + + * For additional environment variables, see FHIR server [Configuration Parameters](fhir/configuration) page. + +1. Start the DSF FHIR Server + Start using: `docker compose up -d && docker compose logs -f` (Ctrl-C will close log, but not stop container) + +### DSF BPE Server +1. Add Group/User + Add group and user used by the DSF BPE java application. Ubuntu compatible commands below: + ``` + sudo groupadd --gid 2202 bpe + sudo useradd --system --no-create-home --uid 2202 --gid 2202 bpe + ``` +1. Download and Extract Config Files + Download and extract prepared DSF BPE server config files and folder structure: + ``` + cd /opt + wget https://dsf.dev/download/dsf_bpe_1_4_0.tar.gz + sudo tar --same-owner -zxvf dsf_bpe_1_4_0.tar.gz + ``` + _The `tar` command will unpack the config files at `/opt/bpe` assuming you changed into the `/opt` directory._ + +1. Verify that the `bpe` system user or group can write into the following folders + * `/opt/bpe/log` + +1. Add certificates and keys + * Add the client certificate (Certificate _B_) and the corresponding private-key to **/opt/bpe/secrets/** + * client_certificate.pem (chmod: 440 chown: bpe:docker) + * client_certificate_private_key.pem (chmod: 440 chown: bpe:docker) + * If the private key is encrypted, add a password file with the password as the only content to **/opt/bpe/secrets/client_certificate_private_key.pem.password** + * If the private key is not encrypted, remove the corresponding docker secret lines from the `docker-compose.yml` file + ``` + L13: - app_client_certificate_private_key.pem.password + ... + L35: DEV_DSF_BPE_FHIR_CLIENT_CERTIFICATE_PRIVATE_KEY_PASSWORD_FILE: /run/secrets/app_client_certificate_private_key.pem.password + ... + L89: app_client_certificate_private_key.pem.password: + L90: file: ./secrets/client_certificate_private_key.pem.password + ``` +1. Modify database passwords + * **/opt/bpe/secrets/db_liquibase.password** + * Generate a random password (min. 32 characters recommended) and replace the content of the file. + * **/opt/bpe/secrets/db_user.password** + * Generate a random password (min. 16 characters recommended) and replace the content of the file. + * **/opt/bpe/secrets/db_user_camunda.password** + * Generate a random password (min. 16 characters recommended) and replace the content of the file. + +1. Modify the docker-compose.yml file and set environment variables to the appropriate values + * **services -> app -> environment:** + * **DEV_DSF_BPE_FHIR_SERVER_BASE_URL**: `https://dsf.todo.organization.com/fhir` + Set your FHIR servers external FQDN, e.g. `foo.bar.de` -> `https://foo.bar.de/fhir` + + * For additional environment variables, see the BPE server [Configuration Parameters](bpe/configuration) page. + +1. Start the DSF BPE Server (without process plugins) + Start using: `docker compose up -d && docker compose logs -f` (Ctrl-C will close log, but not stop container) + +1. Verify DSF BPE Startup + * Check that the BPE was able to download new Task resources from the DSF FHIR server during startup. + * Check that the BPE was able to download a Subscription resource from the DSF FHIR server during startup. + * Check that the BPE was able to connect to the websocket endpoint of the DSF FHIR server during startup. + + If you need to debug the TLS connection to your DSF FHIR server use for example: + `docker run -it --rm alpine/openssl s_client your-fhir-server.fqdn:443` + The command above should print the server certificate of your DSF FHIR server (certificate _A_) and end with a message like `[...]tlsv13 alert certificate required[...]` + + +### Logs +By default, we will log both to the console (collected by docker) and to files in the log directory, so you can use `docker compose logs -f` in `/opt/bpe` and `/opt/fhir` to view informational, warning and error logs. If you encounter any error and the reported information is not detailled enough, you can also check the logs in the `/opt/fhir/log` and `/opt/bpe/log` directories with debugging logs. There, you will also find older log files. If you have any questions and can't resolve them by yourself please always include the latest logs from `/opt/fhir/log` and `/opt/bpe/log` in your support request. + +On a successful BPE start, you should see the following entries in your BPE log: + +``` +INFO Grizzly(1) - ClientEndpoint.onOpen(37) | Websocket connected {uri: wss://FHIR_SERVER_FQDN/fhir/ws, session-id: SOME_RANDOM_UUID1} +INFO Grizzly(1) - ClientEndpoint.onOpen(37) | Websocket connected {uri: wss://FHIR_SERVER_FQDN/fhir/ws, session-id: SOME_RANDOM_UUID2} +``` + +### On-Boarding +Please visit the on boarding website of your network for more information. + +::: tip Ideas for improvement? +Have you found an error or is something unclear to you? Then please feel free to write to us at gth-gecko@hs-heilbronn.de. Thank you very much! +::: diff --git a/docs/src/v1.4.0/maintain/upgrade-from-0.md b/docs/src/v1.4.0/maintain/upgrade-from-0.md new file mode 100644 index 000000000..58dea1a00 --- /dev/null +++ b/docs/src/v1.4.0/maintain/upgrade-from-0.md @@ -0,0 +1,32 @@ +--- +title: Upgrade from DSF 0.9.x +icon: update +--- + +A direct upgrade from DSF 0.9.x to DSF 1.x is not supported. + +:::danger Do not use your 0.9.x configuration as starting point +There are too many changes between DSF 0.9.x and DSF 1.x to use the old configuration as starting point and just adapt some configuration parameter names. + +**Please** use the new installation manual to perform a new installation and use the old setup only for reference. +::: + + +Instead, please perform the following steps: + + +1. Shut down your DSF instances (DSF FHIR Server and DSF BPE). +2. Backup your DSF instances (e.g. by moving the folders `/opt/bpe` and `/opt/fhir` to `/opt/bpe_0.9` and `/opt/fhir_0.9`) +3. Install the new DSF according to the [instructions](install). +4. You can copy **your** certificates (server- and client certificates) to your new installation. Please do **not** copy the CA certificate files from your old installation, as the new version will contain additional CAs (e.g. D-Trust). +5. Configure your processes according to the **new** process plugin [documentation](./install-plugins). You can use your **test** environment configuration and your old production setup configuration for reference. Please ensure to use the **new** configuration parameter names, as many of them will have new prefixes (like `DEV_DSF` instead of `ORG_HIGHMED`). +6. If you perform the installation before the change of the according environment, you can start the old instances again (out of the `/opt/fhir_0.9` and `/opt/bpe_0.9` directories). +7. If you want to replace the old setup with the new one, shutdown the old instances (FHIR + BPE) and start the new ones. + +::: tip New process plugins +Please do not copy your old process plugins into the new DSF. There will be a new release for each process plugin at the time you will be prompted to update your DSF instance. +::: + +::: tip Use your old virtual machine +We recommand the usage of your old DSF 0.9.x virtual machine for your new DSF 1.x setup. This will ensure that you already have the required firewall settings in place. +::: \ No newline at end of file diff --git a/docs/src/v1.4.0/maintain/upgrade-from-1.md b/docs/src/v1.4.0/maintain/upgrade-from-1.md new file mode 100644 index 000000000..905e44c93 --- /dev/null +++ b/docs/src/v1.4.0/maintain/upgrade-from-1.md @@ -0,0 +1,71 @@ +--- +title: Upgrade from DSF 1.3.2 +icon: update +--- + +Upgrading the DSF 1.x to the current version involves modifying the docker-compose.yml files and recreating the containers. + + +::: warning Update to DSF 1.2.0 first +It is important to migrate to [DSF 1.2.0 first](/v1.2.0/maintain/upgrade-from-1). +::: + + +## Modify DSF FHIR Server Setup +1. Preparation / Backup + * We recommend to create a backup of the `/opt/fhir` directory before proceeding with the upgrade. + For example using: `sudo cp -rp /opt/fhir /opt/fhir_backup_pre_1.4.0_upgrade` + +2. Modify the DSF FHIR docker-compose.yml file, replace the version number with 1.4.0. +```diff +version: '3.8' +services: + proxy: +- image: ghcr.io/datasharingframework/fhir_proxy:1.3.2 ++ image: ghcr.io/datasharingframework/fhir_proxy:1.4.0 + restart: on-failure +... + app: +- image: ghcr.io/datasharingframework/fhir:1.3.2 ++ image: ghcr.io/datasharingframework/fhir:1.4.0 + restart: on-failure +... +``` + +3. Upgrade the DSF FHIR containers + From `/opt/fhir` execute + ``` + docker compose up -d && docker compose logs -f + ``` + +## Modify DSF BPE Server Setup +1. Preparation / Backup + * We recommend to create a backup of the `/opt/bpe` directory before proceeding with the upgrade. + For example using: `sudo cp -rp /opt/bpe /opt/bpe_backup_pre_1.4.0_upgrade` + +2. Modify the DSF BPE docker-compose.yml file, replace the version number with 1.4.0. +```diff +version: '3.8' +services: + app: +- image: ghcr.io/datasharingframework/bpe:1.3.2 ++ image: ghcr.io/datasharingframework/bpe:1.4.0 + restart: on-failure +... +``` + +3. Upgrade the DSF BPE containers + From `/opt/bpe` execute + ``` + docker compose up -d && docker compose logs -f + ``` + +4. Verify your upgrade: + * Verify the DSF FHIR server is running in version 1.4.0. The log should contain a message: + `INFO main - BuildInfoReaderImpl.logBuildInfo(137) | Artifact: dsf-fhir-server-jetty, version: 1.4.0, [...]` + * Verify the DSF FHIR server started without errors + * Verify the DSF FHIR server is accessible via https, for example by browsing to https://your-dsf-endpoint.de/fhir/ (authentication with your client-certificate) + * Verify the DSF BPE server is running in version 1.4.0. The log should contain a message: + `INFO main - BuildInfoReaderImpl.logBuildInfo(137) | Artifact: dsf-bpe-server-jetty, version: 1.4.0, [...]` + * Verify the DSF BPE server started without errors + * Verify your install with a ping/pong test diff --git a/docs/src/v1.4.0/process-plugins-advanced.md b/docs/src/v1.4.0/process-plugins-advanced.md new file mode 100644 index 000000000..ccd9c3d99 --- /dev/null +++ b/docs/src/v1.4.0/process-plugins-advanced.md @@ -0,0 +1,4 @@ +--- +title: Process Plugins Advanced +icon: info +--- \ No newline at end of file From 5a7617d39a52b18d3d2e2f60957050ed2db3f92d Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Mon, 18 Dec 2023 19:22:33 +0100 Subject: [PATCH 2/2] 1.4.0 tar.gz files --- .../public/download/dsf_bpe_1_4_0.tar.gz | Bin 0 -> 18257 bytes .../public/download/dsf_fhir_1_4_0.tar.gz | Bin 0 -> 28686 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/src/.vuepress/public/download/dsf_bpe_1_4_0.tar.gz create mode 100644 docs/src/.vuepress/public/download/dsf_fhir_1_4_0.tar.gz diff --git a/docs/src/.vuepress/public/download/dsf_bpe_1_4_0.tar.gz b/docs/src/.vuepress/public/download/dsf_bpe_1_4_0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..1b84fca62edd48782689b84e86c4307974f2c3a8 GIT binary patch literal 18257 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 U%U<@fm;FQg-(f(r9suwF0Mz>qN&o-= literal 0 HcmV?d00001 diff --git a/docs/src/.vuepress/public/download/dsf_fhir_1_4_0.tar.gz b/docs/src/.vuepress/public/download/dsf_fhir_1_4_0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..ef7d24b8b8cd4b6afef213ef54c5a5a954f90e37 GIT binary patch literal 28686 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

mB)FGGy7E5|tvMNByv}YnEXUKkmj$HKm0?8~q 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 QMSX>$yqxrbNQ8v=Ka$Gx?f?J) literal 0 HcmV?d00001