From 2d7721cb581f55dc49e3baeca2411b18dd78ad74 Mon Sep 17 00:00:00 2001 From: Alireza Date: Tue, 19 Sep 2023 10:11:32 -0400 Subject: [PATCH] fix(keyCloak): fix openresty keycloak deployment recipe (#3655) Co-authored-by: Joe Boccanfuso --- .docker/Nginx-Orthanc/config/nginx.conf | 48 --- .docker/Nginx-Orthanc/config/orthanc.json | 89 ------ .docker/Nginx-Orthanc/docker-compose.yml | 23 -- .../volumes/orthanc-db/.gitignore | 2 - package.json | 2 +- .../docker-compose-dcm4che.env | 0 .../docker-compose.yml | 0 .../etc/localtime | 0 .../etc/timezone | 0 .../nginx-proxy/conf/nginx.conf | 0 .../config/nginx.conf | 4 +- .../OpenResty-Orthanc-Keycloak/dockerfile | 35 ++- .../docs/configuration/configurationFiles.md | 2 +- .../configuration/dataSources/dicom-web.md | 4 +- .../docs/deployment/user-account-control.md | 292 ++++++++++++++++++ 15 files changed, 325 insertions(+), 176 deletions(-) delete mode 100644 .docker/Nginx-Orthanc/config/nginx.conf delete mode 100644 .docker/Nginx-Orthanc/config/orthanc.json delete mode 100644 .docker/Nginx-Orthanc/docker-compose.yml delete mode 100644 .docker/Nginx-Orthanc/volumes/orthanc-db/.gitignore rename platform/app/.recipes/{Nginx-Dcm4che => Nginx-Dcm4chee}/docker-compose-dcm4che.env (100%) rename platform/app/.recipes/{Nginx-Dcm4che => Nginx-Dcm4chee}/docker-compose.yml (100%) rename platform/app/.recipes/{Nginx-Dcm4che => Nginx-Dcm4chee}/etc/localtime (100%) rename platform/app/.recipes/{Nginx-Dcm4che => Nginx-Dcm4chee}/etc/timezone (100%) rename platform/app/.recipes/{Nginx-Dcm4che => Nginx-Dcm4chee}/nginx-proxy/conf/nginx.conf (100%) create mode 100644 platform/docs/docs/deployment/user-account-control.md diff --git a/.docker/Nginx-Orthanc/config/nginx.conf b/.docker/Nginx-Orthanc/config/nginx.conf deleted file mode 100644 index c38ee5813d..0000000000 --- a/.docker/Nginx-Orthanc/config/nginx.conf +++ /dev/null @@ -1,48 +0,0 @@ -worker_processes 1; - -events { worker_connections 1024; } - -http { - - upstream orthanc-server { - server orthanc:8042; - } - - server { - listen [::]:80 default_server; - listen 80; - - # CORS Magic - add_header 'Access-Control-Allow-Origin' '*'; - add_header 'Access-Control-Allow_Credentials' 'true'; - add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; - add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH'; - - location / { - - if ($request_method = 'OPTIONS') { - add_header 'Access-Control-Allow-Origin' '*'; - add_header 'Access-Control-Allow_Credentials' 'true'; - add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; - add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH'; - add_header 'Access-Control-Max-Age' 1728000; - add_header 'Content-Type' 'text/plain charset=UTF-8'; - add_header 'Content-Length' 0; - return 204; - } - - proxy_pass http://orthanc:8042; - proxy_redirect off; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Host $server_name; - - # CORS Magic - add_header 'Access-Control-Allow-Origin' '*'; - add_header 'Access-Control-Allow_Credentials' 'true'; - add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; - add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH'; - } - } -} diff --git a/.docker/Nginx-Orthanc/config/orthanc.json b/.docker/Nginx-Orthanc/config/orthanc.json deleted file mode 100644 index 2e10723c04..0000000000 --- a/.docker/Nginx-Orthanc/config/orthanc.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "Name": "Orthanc inside Docker", - "StorageDirectory": "/var/lib/orthanc/db", - "IndexDirectory": "/var/lib/orthanc/db", - "StorageCompression": false, - "MaximumStorageSize": 0, - "MaximumPatientCount": 0, - "LuaScripts": [], - "Plugins": ["/usr/share/orthanc/plugins", "/usr/local/share/orthanc/plugins"], - "ConcurrentJobs": 2, - "HttpServerEnabled": true, - "HttpPort": 8042, - "HttpDescribeErrors": true, - "HttpCompressionEnabled": true, - "DicomServerEnabled": true, - "DicomAet": "ORTHANC", - "DicomCheckCalledAet": false, - "DicomPort": 4242, - "DefaultEncoding": "Latin1", - "DeflatedTransferSyntaxAccepted": true, - "JpegTransferSyntaxAccepted": true, - "Jpeg2000TransferSyntaxAccepted": true, - "JpegLosslessTransferSyntaxAccepted": true, - "JpipTransferSyntaxAccepted": true, - "Mpeg2TransferSyntaxAccepted": true, - "RleTransferSyntaxAccepted": true, - "UnknownSopClassAccepted": false, - "DicomScpTimeout": 30, - - "RemoteAccessAllowed": true, - "SslEnabled": false, - "SslCertificate": "certificate.pem", - "AuthenticationEnabled": false, - "RegisteredUsers": { - "test": "test" - }, - "DicomModalities": {}, - "DicomModalitiesInDatabase": false, - "DicomAlwaysAllowEcho": true, - "DicomAlwaysAllowStore": true, - "DicomCheckModalityHost": false, - "DicomScuTimeout": 10, - "OrthancPeers": {}, - "OrthancPeersInDatabase": false, - "HttpProxy": "", - - "HttpVerbose": true, - - "HttpTimeout": 10, - "HttpsVerifyPeers": true, - "HttpsCACertificates": "", - "UserMetadata": {}, - "UserContentType": {}, - "StableAge": 60, - "StrictAetComparison": false, - "StoreMD5ForAttachments": true, - "LimitFindResults": 0, - "LimitFindInstances": 0, - "LimitJobs": 10, - "LogExportedResources": false, - "KeepAlive": true, - "TcpNoDelay": true, - "HttpThreadsCount": 50, - "StoreDicom": true, - "DicomAssociationCloseDelay": 5, - "QueryRetrieveSize": 10, - "CaseSensitivePN": false, - "LoadPrivateDictionary": true, - "Dictionary": {}, - "SynchronousCMove": true, - "JobsHistorySize": 10, - "SaveJobs": true, - "OverwriteInstances": false, - "MediaArchiveSize": 1, - "StorageAccessOnFind": "Always", - "MetricsEnabled": true, - - "DicomWeb": { - "Enable": true, - "Root": "/dicom-web/", - "EnableWado": true, - "WadoRoot": "/wado", - "Host": "127.0.0.1", - "Ssl": false, - "StowMaxInstances": 10, - "StowMaxSize": 10, - "QidoCaseSensitive": false - } -} diff --git a/.docker/Nginx-Orthanc/docker-compose.yml b/.docker/Nginx-Orthanc/docker-compose.yml deleted file mode 100644 index eba7911a31..0000000000 --- a/.docker/Nginx-Orthanc/docker-compose.yml +++ /dev/null @@ -1,23 +0,0 @@ -version: '3.5' - -services: - orthanc: - image: jodogne/orthanc-plugins:1.11.0 - hostname: orthanc - volumes: - # Config - - ./config/orthanc.json:/etc/orthanc/orthanc.json:ro - # Persist data - - ./volumes/orthanc-db/:/var/lib/orthanc/db/ - ports: - - '4242:4242' # DICOM - - '8042:8042' # Web - restart: unless-stopped - nginx: - image: nginx:latest - volumes: - - ./config/nginx.conf:/etc/nginx/nginx.conf - ports: - - '80:80' #ngnix proxy - depends_on: - - orthanc diff --git a/.docker/Nginx-Orthanc/volumes/orthanc-db/.gitignore b/.docker/Nginx-Orthanc/volumes/orthanc-db/.gitignore deleted file mode 100644 index d6b7ef32c8..0000000000 --- a/.docker/Nginx-Orthanc/volumes/orthanc-db/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/package.json b/package.json index 475147f791..a282575603 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "dev:orthanc": "lerna run dev:orthanc --stream", "dev:dcm4chee": "lerna run dev:dcm4chee --stream", "dev:static": "lerna run dev:static --stream", - "orthanc:up": "docker-compose -f .docker/Nginx-Orthanc/docker-compose.yml up", + "orthanc:up": "docker-compose -f platform/app/.recipes/Nginx-Orthanc/docker-compose.yml up", "preinstall": "node preinstall.js", "start": "yarn run dev", "test": "yarn run test:unit", diff --git a/platform/app/.recipes/Nginx-Dcm4che/docker-compose-dcm4che.env b/platform/app/.recipes/Nginx-Dcm4chee/docker-compose-dcm4che.env similarity index 100% rename from platform/app/.recipes/Nginx-Dcm4che/docker-compose-dcm4che.env rename to platform/app/.recipes/Nginx-Dcm4chee/docker-compose-dcm4che.env diff --git a/platform/app/.recipes/Nginx-Dcm4che/docker-compose.yml b/platform/app/.recipes/Nginx-Dcm4chee/docker-compose.yml similarity index 100% rename from platform/app/.recipes/Nginx-Dcm4che/docker-compose.yml rename to platform/app/.recipes/Nginx-Dcm4chee/docker-compose.yml diff --git a/platform/app/.recipes/Nginx-Dcm4che/etc/localtime b/platform/app/.recipes/Nginx-Dcm4chee/etc/localtime similarity index 100% rename from platform/app/.recipes/Nginx-Dcm4che/etc/localtime rename to platform/app/.recipes/Nginx-Dcm4chee/etc/localtime diff --git a/platform/app/.recipes/Nginx-Dcm4che/etc/timezone b/platform/app/.recipes/Nginx-Dcm4chee/etc/timezone similarity index 100% rename from platform/app/.recipes/Nginx-Dcm4che/etc/timezone rename to platform/app/.recipes/Nginx-Dcm4chee/etc/timezone diff --git a/platform/app/.recipes/Nginx-Dcm4che/nginx-proxy/conf/nginx.conf b/platform/app/.recipes/Nginx-Dcm4chee/nginx-proxy/conf/nginx.conf similarity index 100% rename from platform/app/.recipes/Nginx-Dcm4che/nginx-proxy/conf/nginx.conf rename to platform/app/.recipes/Nginx-Dcm4chee/nginx-proxy/conf/nginx.conf diff --git a/platform/app/.recipes/OpenResty-Orthanc-Keycloak/config/nginx.conf b/platform/app/.recipes/OpenResty-Orthanc-Keycloak/config/nginx.conf index 7360c33610..9e496b79d9 100644 --- a/platform/app/.recipes/OpenResty-Orthanc-Keycloak/config/nginx.conf +++ b/platform/app/.recipes/OpenResty-Orthanc-Keycloak/config/nginx.conf @@ -22,7 +22,7 @@ http { # lua_ settings # - lua_package_path '/usr/local/openresty/lualib/?.lua;;'; + lua_package_path '/usr/local/openresty/lualib/?.lua;;/usr/local/share/lua/5.4/?.lua;;'; lua_shared_dict discovery 1m; # cache for discovery metadata documents lua_shared_dict jwks 1m; # cache for JWKs # lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt; @@ -182,6 +182,8 @@ http { index index.html; try_files $uri $uri/ /index.html; add_header Cache-Control "no-store, no-cache, must-revalidate"; + add_header 'Cross-Origin-Opener-Policy' 'same-origin' always; + add_header 'Cross-Origin-Embedder-Policy' 'require-corp' always; } # EXAMPLE: Reverse Proxy, no auth diff --git a/platform/app/.recipes/OpenResty-Orthanc-Keycloak/dockerfile b/platform/app/.recipes/OpenResty-Orthanc-Keycloak/dockerfile index 490e8f3502..f150a82f49 100644 --- a/platform/app/.recipes/OpenResty-Orthanc-Keycloak/dockerfile +++ b/platform/app/.recipes/OpenResty-Orthanc-Keycloak/dockerfile @@ -28,6 +28,8 @@ FROM node:16.15.0-slim as builder RUN mkdir /usr/src/app WORKDIR /usr/src/app +RUN apt-get update && apt-get install -y build-essential python3 + ENV APP_CONFIG=config/docker_openresty-orthanc-keycloak.js ENV PATH /usr/src/app/node_modules/.bin:$PATH @@ -44,23 +46,38 @@ RUN yarn run build # Stage 2: Bundle the built application into a Docker container # which runs openresty (nginx) using Alpine Linux # LINK: https://hub.docker.com/r/openresty/openresty -FROM openresty/openresty:1.15.8.1rc1-0-alpine-fat +FROM openresty/openresty:1.21.4.2-0-bullseye-fat RUN mkdir /var/log/nginx -RUN apk add --no-cache openssl -RUN apk add --no-cache openssl-dev -RUN apk add --no-cache git -RUN apk add --no-cache gcc +RUN apt-get update && \ + apt-get install -y openssl libssl-dev git gcc wget unzip make&& \ + apt-get clean + +RUN apt-get install --assume-yes lua5.4 libzmq3-dev lua5.4-dev +RUN cd /tmp && \ + wget http://luarocks.org/releases/luarocks-3.9.2.tar.gz && \ + tar zxpf luarocks-3.9.2.tar.gz && \ + cd luarocks-3.9.2 && \ + ./configure && \ + make && \ + make install + # !!! +RUN luarocks install lua-resty-http +# RUN luarocks install lua-nginx-module +RUN luarocks install lua-cjson +RUN luarocks install lua-resty-string +RUN luarocks install lua-resty-session +RUN luarocks install lua-resty-jwt RUN luarocks install lua-resty-openidc +RUN apt-get clean && rm -rf /var/lib/apt/lists/* + # -RUN luarocks install lua-resty-jwt -RUN luarocks install lua-resty-session RUN luarocks install lua-resty-http # !!! -RUN luarocks install lua-resty-openidc -RUN luarocks install luacrypto +RUN luarocks install lua-resty-auto-ssl + # Copy build output to image COPY --from=builder /usr/src/app/platform/app/dist /var/www/html diff --git a/platform/docs/docs/configuration/configurationFiles.md b/platform/docs/docs/configuration/configurationFiles.md index f33ecd671f..0da3cb1699 100644 --- a/platform/docs/docs/configuration/configurationFiles.md +++ b/platform/docs/docs/configuration/configurationFiles.md @@ -274,7 +274,7 @@ output. [dicom-web]: https://en.wikipedia.org/wiki/DICOMweb [storescu]: https://support.dcmtk.org/docs/storescu.html [webpack-proxy]: https://webpack.js.org/configuration/dev-server/#devserverproxy -[orthanc-docker-compose]: https://github.com/OHIF/Viewers/tree/master/.docker/Nginx-Orthanc +[orthanc-docker-compose]: https://github.com/OHIF/Viewers/tree/master/platform/app/.recipes/Nginx-Orthanc [dcm4chee]: https://github.com/dcm4che/dcm4chee-arc-light [dcm4chee-docker]: https://github.com/dcm4che/dcm4chee-arc-light/wiki/Running-on-Docker diff --git a/platform/docs/docs/configuration/dataSources/dicom-web.md b/platform/docs/docs/configuration/dataSources/dicom-web.md index ddc812536f..e5949c72be 100644 --- a/platform/docs/docs/configuration/dataSources/dicom-web.md +++ b/platform/docs/docs/configuration/dataSources/dicom-web.md @@ -74,7 +74,7 @@ _Upload your first Study:_ #### Orthanc: Learn More You can see the `docker-compose.yml` file this command runs at -[`/.docker/Nginx-Orthanc/`][orthanc-docker-compose], and more on +[`/platform/app/.recipes/Nginx-Orthanc`][orthanc-docker-compose], and more on Orthanc for Docker in [Orthanc's documentation][orthanc-docker]. #### Connecting to Orthanc @@ -163,7 +163,7 @@ A boolean indicating if the DICOM upload to the data source is permitted/accepte :::tip The [OHIF plugin for Orthanc](https://book.orthanc-server.com/plugins/ohif.html) by default utilizes the DICOM JSON data source and it has been discovered that only those studies uploaded to Orthanc AFTER the plugin has been installed are -available as DICOM JSON. As such, if the OHIF plugin for Orthanc is desired for studies uploaded prior to installing the plugin, +available as DICOM JSON. As such, if the OHIF plugin for Orthanc is desired for studies uploaded prior to installing the plugin, then consider switching to using [DICOMweb instead](https://book.orthanc-server.com/plugins/ohif.html#using-dicomweb). ::: diff --git a/platform/docs/docs/deployment/user-account-control.md b/platform/docs/docs/deployment/user-account-control.md new file mode 100644 index 0000000000..78c9876fd8 --- /dev/null +++ b/platform/docs/docs/deployment/user-account-control.md @@ -0,0 +1,292 @@ +--- +sidebar_position: 10 +--- +# User Account Control + +> DISCLAIMER! We make no claims or guarantees of this approach's security. If in +> doubt, enlist the help of an expert and conduct proper audits. + +Making a viewer and its medical imaging data accessible on the open web can +provide a lot of benefits, but requires additional security to make sure +sensitive information can only be viewed by authorized individuals. Most image +archives are equipped with basic security measures, but they are not +robust/secure enough for the open web. + +This guide covers one of many potential production setups that secure our +sensitive data. + +## Overview + +This guide builds on top of our +[Nginx + Image Archive guide](/deployment/recipes/nginx--image-archive.md), +wherein we used a [`reverse proxy`](https://en.wikipedia.org/wiki/Reverse_proxy) +to retrieve resources from our image archive (Orthanc). + +To add support for "User Account Control" we introduce +[Keycloak](https://www.keycloak.org/about.html). Keycloak is an open source +Identity and Access Management solution that makes it easy to secure +applications and services with little to no code. We improve upon our +`reverse proxy` setup by integrating Keycloak and Nginx to create an +`authenticating reverse proxy`. + +> An authenticating reverse proxy is a reverse proxy that only retrieves the +> resources on behalf of a client if the client has been authenticated. If a +> client is not authenticated they can be redirected to a login page. + +This setup allows us to create a setup similar to the one pictured below: + +![userControlFlow](../assets/img/user-access-control-request-flow.png) + + + +- All web requests are routed through `nginx` on our `OpenResty` image +- `/pacs` is a reverse proxy for `orthanc`'s `DICOM Web` endpoints + - Requires valid `Authorization: Bearer ` header +- `/pacs-admin` is a reverse proxy for `orthanc`'s Web Admin +- `/auth` is a reverse proxy for `keycloak` +- All static resources for OHIF Viewer are unprotected and accessible. We have + application logic that will redirect unauthenticated users to the appropriate + `keycloak` login screen. + +## Getting Started + +### Requirements + +- Docker + - [Docker for Mac](https://docs.docker.com/docker-for-mac/) + - [Docker for Windows](https://docs.docker.com/docker-for-windows/) + +_Not sure if you have `docker` installed already? Try running `docker --version` +in command prompt or terminal_ + +### Setup + +_Spin Things Up_ + +- Navigate to `/docker/OpenResty-Orthanc-Keycloak` in your shell +- Run `docker-compose up` + +_Create Your First User_ + +- Navigate to: `http://127.0.0.1/auth/admin` +- Sign in with: `admin`/`password` +- From the top left dropdown, select the `Ohif` realm +- From the left sidebar, under `Manage`, select `Users` +- Click `Add User` + - Username: `test` + - Email Verified: `ON` + - Click `Save` +- Click the `Credentials` Tab + - New Password: `test` + - Password Confirmation: `test` + - Temporary: `OFF` + - Click: `Reset Password` +- From the top right dropdown, select `Admin`, then `Sign Out` + +_Sign In_ + +- Navigate to `http://127.0.0.1/` +- Username: `test`, Password: `test` +- Click `Log In` + +_Upload Your First Study_ + +- Navigate to `http://127.0.0.1/pacs-admin` +- If you're not already logged in, use `test`/`test` +- From the top right, select "Upload" +- Click "Select files to upload..." (DICOM) +- Click "Start the upload" +- Navigate back to `http://127.0.0.1/` to view your studies in the Study List + +### Troubleshooting + +_Exit code 137_ + +This means Docker ran out of memory. Open Docker Desktop, go to the `advanced` +tab, and increase the amount of Memory available. + +_Cannot create container for service X_ + +Use this one with caution: `docker system prune` + +_X is already running_ + +Stop running all containers: + +- Win: `docker ps -a -q | ForEach { docker stop $_ }` +- Linux: `docker stop $(docker ps -a -q)` + +### Configuration + +After verifying that everything runs with default configuration values, you will +likely want to update: + +- The domain: `http://127.0.0.1` +- Set secure, non-default passwords +- Regenerate Keycloak Client Secrets + +#### OHIF Viewer + +The OHIF Viewer's configuration is imported from a static `.js` file. The +configuration we use is set to a specific file when we build the viewer, and +determined by the env variable: `APP_CONFIG`. You can see where we set its value +in the `dockerfile` for this solution: + +`ENV APP_CONFIG=config/docker_openresty-orthanc-keycloak.js` + +You can find the configuration we're using here: +`/public/config/docker_openresty-orthanc-keycloak.js` + +To rebuild the `webapp` image created by our `dockerfile` after updating the +Viewer's configuration, you can run: + +- `docker-compose build` OR +- `docker-compose up --build` + +#### Other + +All other files are found in: `/docker/OpenResty-Orthanc-Keycloak/` + +| Service | Configuration | Docs | +| ----------------- | ------------------------------------------------ | ------------------------------------------- | +| OHIF Viewer | [dockerfile][dockerfile] / [config.js][config] | You're reading them now! | +| OpenResty (Nginx) | [`/nginx.conf`][config-nginx] | [lua-resty-openidc][lua-resty-openidc-docs] | +| Orthanc | [`/orthanc.json`][config-orthanc] | [Here][orthanc-docs] | +| Keycloak | [`/ohif-keycloak-realm.json`][config-keycloak]\* | | + +\* These are the seed values for Keycloak. They can be manually updated at +`http://127.0.0.1/auth/admin` + +#### Keycloak Themeing + +The `Login` screen for the `ohif-viewer` client is using a Custom Keycloak +theme. You can find the source files for it in +`/docker/OpenResty-Orthanc-Keycloak/volumes/keycloak-themes/`. You can see how +we add it to Keycloak in the `docker-compose` file, and you can read up on how +to leverage custom themes in +[Keycloak's own docs](https://www.keycloak.org/docs/latest/server_development/index.html#_themes). + +| Default Theme | OHIF Theme | +| ---------------------------------------------------------------------- | ---------------------------------------------------------------- | +| ![Keycloak Default Theme](../assets/img/keycloak-default-theme.png) | ![Keycloak OHIF Theme](../assets/img/keycloak-ohif-theme.png) | + +## Next Steps + +### Deploying to Production + +While these configuration and docker-compose files model an environment suitable +for production, they are not easy to deploy "as is". You can either: + +- Manually recreate this environment and deploy built application files **OR** +- Deploy to a cloud kubernetes provider like + [Digital Ocean](https://www.digitalocean.com/products/kubernetes/) **OR** + - [See a full list of cloud providers here](https://landscape.cncf.io/category=cloud&format=card-mode&grouping=category) +- Find and follow your preferred provider's guide on setting up + [swarms and stacks](https://docs.docker.com/get-started/) + +### Adding SSL + +Adding SSL registration and renewal for your domain with Let's Encrypt that +terminates at Nginx is an incredibly important step toward securing your data. +Here are some resources, specific to this setup, that may be helpful: + +- [lua-resty-auto-ssl](https://github.com/GUI/lua-resty-auto-ssl) +- [Let's Encrypt + Nginx](https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/) + +While we terminate SSL at Nginx, it may be worth using self signed certificates +for communication between services. + +- [SSL Termination for TCP Upstream Servers](https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-tcp/) + +### Use PostgresSQL w/ Orthanc + +Orthanc can handle a large amount of data and requests, but if you find that +requests start to slow as you add more and more studies, you may want to +configure your Orthanc instance to use PostgresSQL. Instructions on how to do +that can be found in the +[`Orthanc Server Book`](http://book.orthanc-server.com/users/docker.html), under +"PostgreSQL and Orthanc inside Docker" + +### Improving This Guide + +Here are some improvements this guide would benefit from, and that we would be +more than happy to accept Pull Requests for: + +- SSL Support +- Complete configuration with `.env` file (or something similar) +- Keycloak Theme improvements +- Any security issues +- One-click deploy to a cloud provider + +## Resources + +### Misc. Helpful Commands + +_Check if `nginx.conf` is valid:_ + +```bash +docker run --rm -t -a stdout --name my-openresty -v $PWD/config/:/usr/local/openresty/nginx/conf/:ro openresty/openresty:alpine-fat openresty -c /usr/local/openresty/nginx/conf/nginx.conf -t +``` + +_Interact w/ running container:_ + +`docker exec -it CONTAINER_NAME bash` + +_List running containers:_ + +`docker ps` + +_Clear Keycloak DB so you can re-seed values:_ + +- `docker volume prune` OR +- `docker volume ls` and `docker volume rm VOLUME_NAME VOLUME_NAME` + +### Referenced Articles + +The inspiration for our setup was driven largely by these articles: + +- [Securing Nginx with Keycloak](https://edhull.co.uk/blog/2018-06-06/keycloak-nginx) +- [Authenticating Reverse Proxy with Keycloak](https://eclipsesource.com/blogs/2018/01/11/authenticating-reverse-proxy-with-keycloak/) +- [Securing APIs with Kong and Keycloak](https://www.jerney.io/secure-apis-kong-keycloak-1/) + +For more documentation on the software we've chosen to use, you may find the +following resources helpful: + +- [Orthanc for Docker](http://book.orthanc-server.com/users/docker.html) +- [OpenResty Guide](http://www.staticshin.com/programming/definitely-an-open-resty-guide/) +- [Lua Ngx API](https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/) +- [Auth0: Picking a Grant Type](https://auth0.com/docs/api-auth/which-oauth-flow-to-use) + +We chose to use a generic OpenID Connect library on the client, but it's worth +noting that Keycloak comes packaged with its own: + +- [oidc-client-js](https://github.com/IdentityModel/oidc-client-js/wiki) +- [Keycloak JavaScript Adapter](https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter) + +If you're not already drowning in links, here are some good security resources +for OAuth: + +- [Diagrams of OpenID Connect Flows](https://medium.com/@darutk/diagrams-of-all-the-openid-connect-flows-6968e3990660) +- [KeyCloak: OpenID Connect Flows](https://www.keycloak.org/docs/latest/securing_apps/index.html#authorization-code) + +For a different take on this setup, check out the repositories our community +members put together: + +- [mjstealey/ohif-orthanc-dimse-docker](https://github.com/mjstealey/ohif-orthanc-dimse-docker) +- [trypag/ohif-orthanc-postgres-docker](https://github.com/trypag/ohif-orthanc-postgres-docker) + + + + + +[orthanc-docs]: http://book.orthanc-server.com/users/configuration.html#configuration +[lua-resty-openidc-docs]: https://github.com/zmartzone/lua-resty-openidc + +[config]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/src/config.js +[dockerfile]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/.recipes/OpenResty-Orthanc-Keycloak/dockerfile +[config-nginx]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/.recipes/OpenResty-Orthanc-Keycloak/config/nginx.conf +[config-orthanc]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/.recipes/OpenResty-Orthanc-Keycloak/config/orthanc.json +[config-keycloak]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/.recipes/OpenResty-Orthanc-Keycloak/config/ohif-keycloak-realm.json +