Send from Modality to Remote Orthanc Instance ?

Exploring options in the case where an Orthanc server is located in the Cloud, rather than in a local intranet onsite.

I know that security and access issues are then potentially a problem, although it looks like some of the settings in the Config file can be setup to add some level of security.

e.g setting the DicomCheckCalledAet to true, and configuring the DicomModalities, but some sort of encryption or a TLS protocol is really neded.

`

Securing the DICOM server

Besides its REST API that is served through its embedded HTTP/HTTPS
server, Orthanc also acts as a DICOM server
(more precisely, as a DICOM SCP).

In general, the DICOM protocol should be disabled if running Orthanc
on a cloud server, except if you use a VPN (cf. reference).
Favor HTTPS for transfering medical images across sites (see
above). You can turn off DICOM protocol by setting the configuration
option DicomServerEnabled to false.

The DICOM modalities that are known to Orthanc are defined by setting
the DicomModalities configuration option. Out-of-the-box, Orthanc
accepts C-ECHO and C-STORE commands sent by unknown modalities, but
blocks C-FIND and C-MOVE commands issued by unknown modalities.

To fully secure the DICOM protocol, you should:

  • Set the DicomAlwaysAllowEcho configuration option to false
    to disallow C-ECHO commands from unknown modalities.

  • Set the DicomAlwaysAllowStore configuration option to false
    to disallow C-STORE commands from unknown modalities.

  • Set the DicomCheckModalityHost configuration option to true
    to validate the IP and hostname address of the remote modalities.

  • For each modality that is defined in DicomModalities,
    selectively specify what DICOM commands are allowed to be issued by
    the SCU of this modality by setting the suboptions AllowEcho,
    AllowFind, AllowMove, AllowStore and AllowGet. For instance, a
    modality could be allowed to C-STORE images, but be disallowed to
    C-FIND the content of Orthanc. Here is a sample configuration to
    define a single modality that is only allowed to send DICOM
    instances to Orthanc:

    {
      "DicomModalities" : {
        "untrusted" : {
          "AET" : "CT",
          "Port" : 104,
          "Host" : "192.168.0.10",
          "AllowEcho" : false,
          "AllowFind" : false,
          "AllowMove" : false,
          "AllowGet" : false,
          "AllowStore" : true
        }
      }
    }
    
    

    Note: These configuration suboptions only affect the behavior of
    the DICOM SCP of Orthanc (i.e. for incoming connections). Orthanc
    will always be able to make outgoing DICOM SCU connections to these
    modalities, independently of the value of these suboptions.

  • Consider implementing a filter implemented in Lua to restrict which modalities can C-STORE images
    within Orthanc, and which kind of images are accepted by Orthanc.

  • Consider setting DicomCheckCalledAet to true to force proper
    configuration of remote modalities.

Remark: As of Orthanc 1.7.1, DICOM TLS encryption is not supported
yet. We are looking for an industrial sponsor to
get this feature implemented, as it is useful in enterprise and cloud
environments.

`

However, there is apparently not yet support for DICOM TLS connections with the current version of Orthanc.

Options would appear to be:

  1. Host Orthanc onsite on an intranet, probably easiest, but requires purchase and maintenance of the local server as opposed to using a dedicated server in the Cloud.

  2. Use a VPN connection or some other “Gateway”, probably second best, but requires setting up and maintaining the VPN. A site-to-stie setup may not be that hard to setup really.

  3. I did notice that you can temporarily use port forwarding by ssh -L 8042:127.0.0.1:8042 user(at)remote.domain_ip.com (then user pass) on a LINUX or OX S system to access the remote Orthanc REST and remote Orthanc Explorer from a local machine, since it forwards the request to the remote host. That works, and is convenient to access the Explorer remotely when remote access is disabled and there is no way to bypass a proxy. I have not tried that for port 4242, but presumably that might also work for DICOM. Not a solution, but would that sort of simulate a VPN for testing purposes ?

What is the status of the TLS feature?

It isn’t clear to me that it is possible to send a study from an acquisition device to a remote Orthanc Server using the REST API, rather than DICOM, unless there is some sort of DICOM → REST API gateway on the local intranet.

Thanks.

Hi,

What we have experienced at Osimis when deploying Orthanc in the cloud for a customer, is to expose Orthanc through an ingress controller (nginx) with client-side certification:

`

server {
server_name $thedomainnameofthecustomertoaccessorthanc;

client certificate

ssl_client_certificate /etc/nginx/client_certs/ca.crt;
ssl_verify_client on;

set $ihpnginxorthanc $dockercontainernameoforthanc;
location / {
rewrite /(.*) /orthanc/$1 break;
include /etc/nginx/includes/proxy.conf;
proxy_pass http://$ihpnginxorthanc;
}

access_log off;
error_log /var/log/nginx/error.log error;
}

`

Where the proxy.conf file is set like this:

proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header forwarded "host=$http_host;proto=$scheme"; proxy_buffering off; proxy_request_buffering off; proxy_http_version 1.1; proxy_intercept_errors on; client_max_body_size 0;

With this pretty simple setup, Orthanc access is secured.

Now for the DICOM TLS part, we have somehow set it up with stunnel to send studies with DICOM to a remote Treatment Planning System.
The solution is working but is using PSK key authentication instead of auto-renewed certificates to a specific domain name which would secure it even more, as we now have to manually rotate the PSK key to ensure the connection stays secured.

In folder ./stunnel:

  • file Dockerfile:

`

FROM alpine:3.11

ARG VERSION=5.56

ENV STUNNEL_URL https://www.stunnel.org/downloads/stunnel-$VERSION.tar.gz

ENV STUNNEL_FILE stunnel-$VERSION.tar.gz
ENV STUNNEL_TEMP stunnel-$VERSION-build
ENV STUNNEL_DEPS openssl
ENV BUILD_DEPS curl alpine-sdk openssl-dev

RUN set -xe
&& apk update
&& apk add $STUNNEL_DEPS $BUILD_DEPS
&& mkdir $STUNNEL_TEMP
&& cd $STUNNEL_TEMP
&& curl -sSL $STUNNEL_URL -o $STUNNEL_FILE
&& tar -xf $STUNNEL_FILE --strip 1
&& ./configure
&& make install
&& cd …
&& rm -rf $STUNNEL_TEMP $STUNNEL_FILE
&& apk --purge del $BUILD_DEPS
&& mkdir -p /etc/stunnel/

WORKDIR /etc/stunnel

CMD [“stunnel”, “config/stunnel.conf”]
COPY stunnel.conf config/stunnel.conf

`

  • file stunne.conf (replace $port and $ipaddress by your values of the target host where you can install the stunnel server):

`

foreground = yes
client = yes

[DICOM_TO_TPS]
accept = 2762

connect = $ipaddress:$port
PSKsecrets = /path/to/secret/psk.txt

`

In folder .:

  • docker-compose.yml file extract:

`

orthanc:
image: osimis/orthanc
environment:
DICOM_MODALITIES: { “tps”: [“TPS”, “stunnel-out”, 2762] }

stunnel-out:
build: stunnel

this volume store the psk.txt file

volumes: [“stunnel-out-secrets:/path/to/secret”]

`

On the target host ($port and $ipaddress mentioned above) we have deployed the following (with a bit more advanced way of handling the stunnel container not to have to rebuilt it at each configuration change):

  • folder ., file docker-compose.yml (replace $port with the same value as targetted before and $tpsipaddress and $tpsport with the values of your target DICOM resource) (the psk.txt file is the same as the one mentioned above of course):

`

version: “2”

services:
stunnel-in:

restart: unless-stopped
build: stunnel
volumes: [“stunnel-in:/etc/stunnel”]
ports: [“$port:2762”]

environment:
DESTINATIONS: |
[
{
“Title”: “DICOM_TO_TPS”,
“Accept”: 2762,
“Connect”: “$tpsipaddress:$tpsport”,
“PSKsecrets”: “/etc/stunnel/psk.txt”
}
]

volumes:
stunnel-in:

`

  • iIn folder ./stunnel:
  • file Dockerfile:

`

FROM alpine:3.11

ARG VERSION=5.56

ENV STUNNEL_URL https://www.stunnel.org/downloads/stunnel-$VERSION.tar.gz

ENV STUNNEL_FILE stunnel-$VERSION.tar.gz
ENV STUNNEL_TEMP stunnel-$VERSION-build
ENV STUNNEL_DEPS openssl
ENV BUILD_DEPS curl alpine-sdk openssl-dev

RUN set -xe
&& apk update
&& apk add $STUNNEL_DEPS $BUILD_DEPS jq
&& mkdir $STUNNEL_TEMP
&& cd $STUNNEL_TEMP
&& curl -sSL $STUNNEL_URL -o $STUNNEL_FILE
&& tar -xf $STUNNEL_FILE --strip 1
&& ./configure
&& make install
&& cd …
&& rm -rf $STUNNEL_TEMP $STUNNEL_FILE
&& apk --purge del $BUILD_DEPS
&& mkdir -p /etc/stunnel/

COPY docker-entrypoint.sh /entrypoint.sh

ENTRYPOINT [“/entrypoint.sh”]

`

  • file docker-entrypoint.sh (with exec rights on the file):

`

#!/bin/sh

cd /etc/stunnel

cat > stunnel.conf <<EOF
client = no
foreground = yes
EOF

for destination in $(echo “${DESTINATIONS}” | jq -c ‘.’); do
echo “[”$(echo ${destination} | jq -r ‘.Title’)“]” >> stunnel.conf
echo "accept = "$(echo ${destination} | jq -r ‘.Accept’) >> stunnel.conf
echo "connect = "$(echo ${destination} | jq -r ‘.Connect’) >> stunnel.conf
echo “ciphers = PSK” >> stunnel.conf
echo "PSKsecrets = "$(echo ${destination} | jq -r ‘.PSKsecrets’) >> stunnel.conf
done

exec stunnel stunnel.conf

`

The target host is our setup is running on a dedicated host and not on the one with the target DICOM resource because we don’t maintaint the DICOM resource, but it could run all on one host of course.

We are not stunnel experts at Osimis, so there might be a cleaner/simpler way of handling it, but this setup has allowed us so far to send studies from an Orthanc in the cloud to a target DICOM resource using the DICOM protocol through TLS using stunnel.

In our case, our Orthanc server is not receiving in DICOM through stunnel, but sending in DICOM through stunnel, but you can easily reproduce our setup to have Orthanc receiving in DICOM through stunnel.

Other option for you would be to use DICOMweb if possible.

I hope this helps.

Kind regards,

Michel

Hello,

Just a small complement to Michel’s great, extremely complete answer.

Stephen asked:

What is the status of the TLS feature?

This feature is pending on our roadmap. We are just looking for financial support from the industry to develop it, as written in the Orthanc Book:

https://book.orthanc-server.com/faq/security.html#securing-the-dicom-server

Sébastien-

Michel,

Thanks a lot for the information ! That is really helpful !

I’ll have to look into that. Not really a networking expert, but getting better. I have been learning a bit about NGINX and OpenResty.

I’m running a compiled version of the latest Orthanc on an UBUNTU dev server with PSQL, DicomWeb and a few other plug-ins, so no Docker files.

Stunnel is apparently easy to add to UBUNTU: stunnel for UBUNTU so I mgiht at least do that to see how it works. I’ve been spending tons of time trying out various configurations.

I have been playing around with OpenResty (NGINX), but for a different purpose. Was trying to see if there is away to provide access to the Orthanc Osimis Viewer and OHIF viewer to users (i.e. patients & referring docs, but only for particular uuid’s). That brings up a slew of issues, but it apparently is possible to use the http_auth_module to query on authentication server to filter out requests through the proxy. That actually does work, but setting up the auth mechanism is a little tedious, and there are a myriad of ways to to that, and some potential problems. Not sure we would use that, but it it interesting to try to implement. I played around with the Osimis Advanced Auth Plug-in, but OpenResty / NGINX seems to provide a little more flexibility.

I haven’t tried the setup that you show for NGINX, although that looks pretty simple, but it allows access to just a single client ? Can you specify a port with that setup (e.g DICOM port), so it applies only to the DICOM port ?

In the arrangement that I am talking about, I would want bidrectional communication betweens an MRI scanner and the Orthanc Instance, over the internet using whatever DICOM port they want to use. In fact, there is a reading workstation co-locateed with the MRI scanner, so we would want to be able to push and pull studies from there as well. Not sure what kind of protocols the MRI scanner supports, but I have the conformance statement. I doubt that it has built-in TLS, and I doubt that the workstation does either. I use OSIRIX sometimes, but not in a clinical environment. I think that does have TLS support.

Would it not be possible to just use a VPN connection or stunnel without NGINX in that case ? (.e.g relay the MRI scanner through another local server with VPN or stunnel to the UBUNTU server that is also running VPN or stunnel, so that the DICOM does not need to be encrypted or https). I do have access to the dedicated server, as well as access to IT resources where the MRI scanner is located. Seems like building a software gateway on the UBUNTU server, and a hardware/software gateway on the other end where the MRI scanner is might work. You can actually put stunnel on a Rasberry Pi: How to build stunnel for Raspberry Pi

Like I say, have not used stunnel previously, but sounds like it provides a functionality similar to a VPN connection ?

Again, thanks a lot for the well-crafted response.

Stephen,

An ingress controller wil still be required to secure your Orthanc server running in the cloud.

Besides this, you can definitely setup a VPN connection that might ease the whole setup in your case actually.
In our case with stunnel and client side certification, we were willing to secure the connection with 5 other hosts that are gateways to DICOM resources of the 5 institutions.
Your case looks simpler though, and if you setup a VPN, then indeed, you could send data through the VPN tunnel in DICOM.

I guess you’ll have to dig into it on your own.

I’m looking forward to reading from you once you’ve got a running setup.

Kind regards,

Michel