Skip to content

Run secured archive services on a single host

Gunter Zeilinger edited this page Apr 25, 2024 · 11 revisions
Secured Archive services using Keycloak as Authentication Server.

Ensure that there is a hostname entry in your DNS server for the docker host.
(Optional) Create system groups and users with particular group and user IDs used by the archive services on the host
$ sudo -i
# groupadd -r slapd-dcm4chee --gid=1021 && useradd -r -g slapd-dcm4chee --uid=1021 slapd-dcm4chee
# groupadd -r postgres-dcm4chee --gid=999 && useradd -r -g postgres-dcm4chee --uid=999 postgres-dcm4chee
# groupadd -r dcm4chee-arc --gid=1023 && useradd -r -g dcm4chee-arc --uid=1023 dcm4chee-arc
# groupadd -r keycloak-dcm4chee --gid=1029 && useradd -r -g keycloak-dcm4chee --uid=1029 keycloak-dcm4chee
# exit

Continue using Docker Command Line or Docker Compose alternatively:

  1. Create an user-defined bridge network
    $ docker network create dcm4chee_network
    
  2. Start OpenLDAP Server as described in Run minimum set of archive services on a single host.
  3. Start MariaDB Server used by Keycloak Authentication Server

    Launch a container providing Maria DB Server into the created network, e.g:

    $ docker run --network=dcm4chee_network --name mariadb \
               -p 3306:3306 \
               -e MYSQL_ROOT_PASSWORD=secret \
               -e MYSQL_DATABASE=keycloak \
               -e MYSQL_USER=keycloak \
               -e MYSQL_PASSWORD=keycloak \
               -v /etc/localtime:/etc/localtime:ro \
               -v /etc/timezone:/etc/timezone:ro \
               -v /var/local/dcm4chee-arc/mysql:/var/lib/mysql \
               -d mariadb:10.11.4
    

    Publishing MariaDB Server port 3306 from the container to the host by -p 3306:3306 enables to access the MariaDB Server also by external MariaDB/MySQL clients. It is not required for running Keycloak, because the Keycloak container connects the Server port of the MariaDB Server container over the created bridge network.

    -e MYSQL_ROOT_PASSWORD=secret
    -e MYSQL_DATABASE=keycloak \
    -e MYSQL_USER=keycloak \
    -e MYSQL_PASSWORD=keycloak \
    

    set the password of the MariaDB root superuser account, the name of the database, a user and its password.

    See further available environment variables of the MariaDB container.

    Bind mount -v /etc/localtime:/etc/localtime:ro and -v /etc/timezone:/etc/timezone:ro duplicates your host timezone inside the container. Otherwise, the container timezone is UTC. Attention: If there is no /etc/timezone on your host, you have to create one (e.g.: $ echo "Europe/Vienna" > /etc/timezone) before launching the container, otherwise the container will not start.

    Bind mount -v /var/local/dcm4chee-arc/mysql:/var/lib/mysql takes care to store the database in the specified host directory. It is initialized on first container start-up if it is not already present in the specified host directory. That ensures that the data does not get lost on deletion and re-creation of the MariaDB Server container.

  4. Start Keycloak Authentication Server

    Launch a container providing preconfigured Keycloak Authentication Server into the created network, e.g:

    $ docker run --network=dcm4chee_network --name keycloak \
               -p 8843:8843 \
               -e KC_HTTPS_PORT=8843 \
               -e KC_HOSTNAME=<docker-host> \
               -e KEYCLOAK_ADMIN=admin \
               -e KEYCLOAK_ADMIN_PASSWORD=changeit \
               -e KC_DB: mariadb
               -e KC_DB_URL_DATABASE: keycloak
               -e KC_DB_URL_HOST: mariadb
               -e KC_DB_USERNAME: keycloak
               -e KC_DB_PASSWORD: keycloak
               -e KC_LOG=file \
               -e ARCHIVE_HOST=<docker-host> \
               -e KEYCLOAK_WAIT_FOR=ldap:389 mariadb:3306 \
               -v /etc/localtime:/etc/localtime:ro \
               -v /etc/timezone:/etc/timezone:ro \
               -v /var/local/dcm4chee-arc/keycloak:/opt/keycloak/data \
               -d dcm4che/keycloak:24.0.3
    
    -p 8843:8843 \
    

    publishes the https (8843) port of Keycloak from the container to the host to enable connections from external https clients to Keycloak.

    The port number is set by:

    -e KC_HTTPS_PORT=8843 \
    

    to avoid collisions with the https port used by Wildfly with the deployed dcm4che Archive 5 application by default.

    -e KC_HOSTNAME=<docker-host> \
    

    specifies the public host name of the Keycloak server.

    -e KEYCLOAK_ADMIN=admin \
    -e KEYCLOAK_ADMIN_PASSWORD=changeit \
    

    is required to create an admin account to be able to login to the admin console of the Keycloak master realm at https://${KC_HOSTNAME}:${KC_HTTPS_PORT}[/${KC_HTTP_RELATIVE_PATH}]. Once the first user with administrative rights exists, you may use the UI to change the password or create additional admin users and/or delete that initial admin user.

    -e KC_DB: mariadb
    -e KC_DB_URL_DATABASE: keycloak
    -e KC_DB_URL_HOST: mariadb
    -e KC_DB_USERNAME: keycloak
    -e KC_DB_PASSWORD: keycloak
    

    specifies the database vendor, name, host, user name and password of the database used by Keycloak. KC_DB_URL_DATABASE, KC_DB_USERNAME and KC_DB_PASSWORD have to match with the values set for MYSQL_DATABASE, MYSQL_USER and MYSQL_PASSWORD on launching the MariaDB Server container, and KC_DB_URL_HOST have to match with its container name.

    KC_LOG=file
    

    enables logging to file /opt/keycloak/data/keycloak.log, instead of logging to the standard output.

    If you set the environment variables LDAP_BASE_DN, LDAP_ROOTPASS for the LDAP server container, you have to set that environment variables also for the Keycloak container. Otherwise Keycloak will fail to connect to the LDAP Server.

    -e ARCHIVE_HOST=<docker-host> \
    

    specify the public hostname of the archive device referred by OIDC Keycloak clients for securing the UI and the Wildfly Administration Console of the archive initialized on first startup. You have to replace <docker-host> by the hostname of the docker host, which must be resolvable by your DNS server.

    -e KEYCLOAK_WAIT_FOR=ldap:389 mariadb:3306 delays the start of Keycloak until OpenLDAP slapd and MariaDB server is listening on the specified ports, which prevents error on restart of all containers caused by failures to connect LDAP by Keycloak, before OpenLDAP slapd and MariaDB server is ready to accept connections.

    For further available environment variables of the Keycloak container see https://github.com/dcm4che-dockerfiles/keycloak-quarkus#environment-variables.

    Bind mount -v /etc/localtime:/etc/localtime:ro and -v /etc/timezone:/etc/timezone:ro duplicates your host timezone inside the container. Otherwise the container timezone is UTC. Attention: If there is no /etc/timezone on your host, you have to create one (e.g.: $ echo "Europe/Vienna" > /etc/timezone) before launching the container, otherwise the container will not start.

    Bind mount -v /var/local/dcm4chee-arc/keycloak:/opt/keycloak/data maps Keycloak log and temporary files to the specified host directory.

    By default the https service will use the certificate for handling TLS connections. To avoid the security warning of Web Browsers accessing the Keycloak UI or the WildFly Administration Console, you have to provide a certificate which Common Name and/or Subject Alt Name matches the host name and which is signed by a trusted issuer in a keystore file in PKCS #12 or Java KeyStore (JKS) format, bind mount the file or its containing directory into the container, and refer it by environment variable KC_HTTPS_KEY_STORE_FILE.

    Check the Keycloak server log if Keycloak started successfully:

    $ tail -f /var/local/dcm4chee-arc/keycloak/log/keycloak.log 
    2022-06-09 16:06:19,360 INFO  [org.jgroups.protocols.pbcast.GMS] (keycloak-cache-init) 875d7be6d885-1337: no members discovered after 2002 ms: creating cluster as coordinator
    2022-06-09 16:06:19,369 INFO  [org.infinispan.CLUSTER] (keycloak-cache-init) ISPN000094: Received new cluster view for channel ISPN: [875d7be6d885-1337|0] (1) [875d7be6d885-1337]
    2022-06-09 16:06:19,373 INFO  [org.infinispan.CLUSTER] (keycloak-cache-init) ISPN000079: Channel `ISPN` local address is `875d7be6d885-1337`, physical addresses are `[172.21.0.3:44392]`
    2022-06-09 16:06:19,873 INFO  [org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory] (main) Node name: 875d7be6d885-1337, Site name: null
    2022-06-09 16:06:19,935 INFO  [org.keycloak.services] (main) KC-SERVICES0050: Initializing master realm
    2022-06-09 16:06:22,169 INFO  [org.keycloak.services] (main) KC-SERVICES0004: Imported realm dcm4che from file /opt/keycloak/bin/../data/import/dcm4che-realm.json.
    2022-06-09 16:06:22,405 INFO  [org.keycloak.services] (main) KC-SERVICES0009: Added user 'admin' to realm 'master'
    2022-06-09 16:06:22,719 INFO  [io.quarkus] (main) Keycloak 19.0.1 on JVM (powered by Quarkus 2.7.5.Final) started in 8.238s. Listening on: https://0.0.0.0:8843
    2022-06-09 16:06:22,719 INFO  [io.quarkus] (main) Profile prod activated. 
    2022-06-09 16:06:22,719 INFO  [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, jdbc-h2, jdbc-mariadb, jdbc-mssql, jdbc-mysql, jdbc-oracle, jdbc-postgresql, keycloak, logging-gelf, narayana-jta, reactive-routes, resteasy, resteasy-jackson, smallrye-context-propagation, smallrye-health, smallrye-metrics, vault, vertx]

    See further environment variables of Keycloak

  5. Start PostgreSQL Server as described in Run minimum set of archive services on a single host.
  6. Start Wildfly with deployed dcm4che Archive 5 application

    Launch a container providing Wildfly with deployed dcm4che Archive 5 application into the created network, e.g:

    $ docker run --network=dcm4chee_network --name arc \
               -p 8080:8080 \
               -p 8443:8443 \
               -p 9990:9990 \
               -p 9993:9993 \
               -p 11112:11112 \
               -p 2762:2762 \
               -p 2575:2575 \
               -p 12575:12575 \
               -e POSTGRES_DB=pacsdb \
               -e POSTGRES_USER=pacs \
               -e POSTGRES_PASSWORD=pacs \
               -e AUTH_SERVER_URL=https://keycloak:8843 \
               -e UI_AUTH_SERVER_URL=https://<docker-host>:8843 \
               -e WILDFLY_WAIT_FOR="ldap:389 db:5432 keycloak:8843" \
               -v /etc/localtime:/etc/localtime:ro \
               -v /etc/timezone:/etc/timezone:ro \
               -v /var/local/dcm4chee-arc/wildfly:/opt/wildfly/standalone \
               -d dcm4che/dcm4chee-arc-psql:5.32.0-secure
    

    which differs from Run minimum set of archive services on a single host only by

    • -e AUTH_SERVER_URL=https://keycloak:8843 - ensures, that the archive connects to the keycloak container via the bridge network using the right port, specified by keycloak container -e KC_HTTPS_PORT=8843,
    • -e UI_AUTH_SERVER_URL=https://<docker-host>:8843 - you have to replace <docker-host> by the hostname of the docker host, which must be resolvable by your DNS server - and
    • -d dcm4che/dcm4chee-arc-psql:5.32.0-secure - to select the Docker image for the Archive with secured UI and secured RESTful services. If you want to secure the Archive UI without securing the RESTful services use -d dcm4che/dcm4chee-arc-psql:5.32.0-secure-ui instead.

    If you set the environment variables REALM_NAME or SSL_REQUIRED for the Keycloak server container, you have to set that environment variables also for the Archive container. Otherwise the background out of band REST invocation to Keycloak for user authorization will fail.

    If you want to run more than one Archive container, you have to specify different values for environment variable UI_CLIENT_ID (default: dcm4chee-arc-ui), and register each of the Archive UIs in Keycloak.

    See further environment variables of Archive

  7. Verify OIDC client for Archive UI in Keycloak

    Sign in with User/Password root/changeit at the Realm Admin Console of Keycloak at https://<docker-host>:8843/admin/dcm4che/console Note :

    • Replace <docker-host> by the hostname of the docker host.
    • If you changed the default realm name dcm4che by environment variable REALM_NAME for Keycloak and Archive Containers, replace dcm4che by that value in the URL.

    Keycloak docker image dcm4che/keycloak:24.0.3 and newer creates an OIDC client for the Archive UI on first startup, customizable by environment variables :

    Only users with role user are permitted to access the Archive UI and RESTful services. Depending on the UI Permission Configuration particular UI features are restricted to additional user roles. Users with role root - or the value specified by environment variable SUPER_USER_ROLE for the Archive container - have access to all UI features, independent of their other roles and configured UI Permissions.

    Sign out, before verifying that accessing the Archive UI at http://<docker-host>:8080/dcm4chee-arc/ui2 or https://<docker-host>:8443/dcm4chee-arc/ui2 will redirect you to the Login page of Keycloak. You may sign in with User/Password root/changeit, admin/changeit or user/changeit.

    Every user can change her password and other account settings via Edit Account in the Sign-in Tools in the upper right corner of the Archive UI. Users with realm-management -> view-realm role mapped to them, also have a link Admin Realm to view the Keycloak Realm Admin Console.

    Only users with all roles specified by client realm-management are permitted to access the Keycloak Administration Console and perform administration changes.

  8. Verify OIDC client for Wildfly Administration Console in Keycloak

    Access to the Wildfly Administration Console is also protected with Keycloak.

    Keycloak docker image dcm4che/keycloak:24.0.3 and newer creates also another OIDC client for the Wildfly Administration Console on first startup, customizable by environment variables WILDFLY_CONSOLE, ARCHIVE_HOST and ARCHIVE_MANAGEMENT_HTTPS_PORT:

    Only users with role ADMINISTRATOR are permitted to access the WildFly Administration Console.

    Sign out, before verifying that accessing the WildFly Administration Console at http://<docker-host>:9990 or https://<docker-host>:9993 will redirect you to the Login page of Keycloak. You may sign in with User/Password root/changeit.

  9. (Optional) Change preconfigured users and roles

    Secured archive setup has pre-configured users / roles intended for different purposes - refer Secure Archive Users and Roles.

    Optionally, add separate users for Keycloak / Wildfly administration to decouple roles / responsibilities of archive root user :

    Name Password Role(s)
    wildfly-admin changeit user
    ADMINISTRATOR
    keycloak-admin changeit user
    all roles specified by client realm-management

    using scripts :

    • add-keycloak-admin

      $ docker exec ldap add-keycloak-admin keycloak-admin changeit
      adding new entry "uid=keycloak-admin,ou=users,dc=dcm4che,dc=org"
      modifying entry "cn=user,ou=users,dc=dcm4che,dc=org"
      modifying entry "cn=create-client,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=impersonation,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=manage-authorization,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=manage-clients,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=manage-events,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=manage-identity-providers,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=manage-realm,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=manage-users,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=realm-admin,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=view-authorization,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=view-clients,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=view-events,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=view-identity-providers,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=view-realm,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=view-users,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=query-users,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=query-groups,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=query-realms,ou=realm-management,dc=dcm4che,dc=org"
      modifying entry "cn=query-clients,ou=realm-management,dc=dcm4che,dc=org"
      
    • add-wildfly-admin

      $ docker exec ldap add-wildfly-admin wildfly-admin changeit
      adding new entry "uid=wildfly-admin,ou=users,dc=dcm4che,dc=org"
      modifying entry "cn=user,ou=users,dc=dcm4che,dc=org"
      modifying entry "cn=ADMINISTRATOR,ou=users,dc=dcm4che,dc=org"
      

      resulting in

    By default, root user has ADMINISTRATOR as well as all roles specified by client realm-management:

    to allow full access to the Realm Admin Console of Keycloak and Wildfly Administration Console. If decoupling of management functions is required by your application, log in to Keycloak Admin Console at https://<docker-host>:8843/admin/dcm4che/console with keycloak-admin user and unassign ADMINISTRATOR and realm-management client role mappings from root user.

    will result in

    By default, the Import Users is turned ON which ensures import of LDAP users into Keycloak DB and synced by configured sync policies. Additionally, Sync Registrations is also turned ON to add new users created by Keycloak in LDAP. Both these settings can be verified by navigating to User Federation >> Ldap and navigating to Synchronization Settings in the Ldap Settings tab

    and edit, delete or add new users by navigating to Users:

    You may add additional Realm Roles associated with particular UI Permission Configuration and assign them to users to grant them the associated UI Permissions. (Users with role root - or the value specified by environment variable SUPER_USER_ROLE for the Archive container - have access to all UI features, independent of their other roles and configured UI Permissions.)

  10. (Optional) Send CT images to the Archive using dcm4che/dcm4che-tools as described in Run minimum set of archive services on a single host.
  11. You may stop all 5 containers by:
    $ docker stop ldap mariadb keycloak db arc
    

    and start all 5 containers again by:

    $ docker start ldap mariadb keycloak db arc
    
  12. You may delete the stopped containers by
    $ docker rm -v ldap mariadb keycloak db arc
    

    You may delete the created bridge network by

    $ docker network rm dcm4chee_network
    

Alternatively to Docker Command Line one may use Docker Compose to take care for starting all 4 containers:

  1. Specify the services in a configuration file docker-compose.yml (e.g.):
    version: "3"
    services:
      ldap:
        image: dcm4che/slapd-dcm4chee:2.6.5-32.0
        logging:
          driver: json-file
          options:
            max-size: "10m"
        ports:
          - "389:389"
          - "636:636"
        environment:
          STORAGE_DIR: /storage/fs1
        volumes:
          - /var/local/dcm4chee-arc/ldap:/var/lib/openldap/openldap-data
          - /var/local/dcm4chee-arc/slapd.d:/etc/openldap/slapd.d
      mariadb:
        image: mariadb:10.11.4
        logging:
          driver: json-file
          options:
            max-size: "10m"
        ports:
          - "3306:3306"
        environment:
          MYSQL_ROOT_PASSWORD: secret
          MYSQL_DATABASE: keycloak
          MYSQL_USER: keycloak
          MYSQL_PASSWORD: keycloak
        volumes:
          - /etc/localtime:/etc/localtime:ro
          - /etc/timezone:/etc/timezone:ro
          - /var/local/dcm4chee-arc/mysql:/var/lib/mysql
      keycloak:
        image: dcm4che/keycloak:24.0.3
        logging:
          driver: json-file
          options:
            max-size: "10m"
        ports:
          - "8843:8843"
        environment:
          KC_HTTPS_PORT: 8843
          KC_HOSTNAME: <docker-host>
          KEYCLOAK_ADMIN: admin
          KEYCLOAK_ADMIN_PASSWORD: changeit
          KC_DB: mariadb
          KC_DB_URL_DATABASE: keycloak
          KC_DB_URL_HOST: mariadb
          KC_DB_USERNAME: keycloak
          KC_DB_PASSWORD: keycloak
          KC_LOG: file
          ARCHIVE_HOST: <docker-host>
          KEYCLOAK_WAIT_FOR: ldap:389 mariadb:3306
        depends_on:
          - ldap
          - mariadb
        volumes:
          - /etc/localtime:/etc/localtime:ro
          - /etc/timezone:/etc/timezone:ro
          - /var/local/dcm4chee-arc/keycloak:/opt/keycloak/data
      db:
        image: dcm4che/postgres-dcm4chee:16.2-32
        logging:
          driver: json-file
          options:
            max-size: "10m"
        ports:
          - "5432:5432"
        environment:
          POSTGRES_DB: pacsdb
          POSTGRES_USER: pacs
          POSTGRES_PASSWORD: pacs
        volumes:
          - /etc/localtime:/etc/localtime:ro
          - /etc/timezone:/etc/timezone:ro
          - /var/local/dcm4chee-arc/db:/var/lib/postgresql/data
      arc:
        image: dcm4che/dcm4chee-arc-psql:5.32.0-secure
        ports:
          - "8080:8080"
          - "8443:8443"
          - "9990:9990"
          - "9993:9993"
          - "11112:11112"
          - "2762:2762"
          - "2575:2575"
          - "12575:12575"
        environment:
          POSTGRES_DB: pacsdb
          POSTGRES_USER: pacs
          POSTGRES_PASSWORD: pacs
          AUTH_SERVER_URL: https://keycloak:8843
          UI_AUTH_SERVER_URL: https://<docker-host>:8843
          WILDFLY_CHOWN: /storage
          WILDFLY_WAIT_FOR: ldap:389 db:5432 keycloak:8843
        depends_on:
          - ldap
          - keycloak
          - db
        volumes:
          - /etc/localtime:/etc/localtime:ro
          - /etc/timezone:/etc/timezone:ro
          - /var/local/dcm4chee-arc/wildfly:/opt/wildfly/standalone
          - /var/local/dcm4chee-arc/storage:/storage

    you have to replace <docker-host> by the hostname of the docker host, which must be resolvable by your DNS server.

    See all available environment variables for containers :

    Note : If there are difficulties starting the archive service due to

    There is insufficient memory for the Java Runtime Environment to continue. Cannot create GC thread. Out of system resources.
    

    adding the following option to the arc service

    security_opt:
     - seccomp:unconfined
    
  2. Create and start the 5 containers by invoking
    $ docker-compose -p dcm4chee up -d
    Creating network "dcm4chee_default" with the default driver
    Creating dcm4chee_ldap_1    ... done
    Creating dcm4chee_mariadb_1 ... done
    Creating dcm4chee_db_1      ... done
    Creating dcm4chee_keycloak_1 ... done
    Creating dcm4chee_arc_1      ... done

    in the directory containing docker-compose.yml.

  3. Register the Archive UI as OIDC client in Keycloak as described above.
  4. Register the WildFly Administration Console as OIDC client in Keycloak as described above.
  5. You may stop all 5 containers by:
    $ docker-compose -p dcm4chee stop
    Stopping dcm4chee_arc_1      ... done
    Stopping dcm4chee_keycloak_1 ... done
    Stopping dcm4chee_ldap_1     ... done
    Stopping dcm4chee_mariadb_1  ... done
    Stopping dcm4chee_db_1       ... done

    and start all 5 containers again by:

    $ docker-compose -p dcm4chee start
    Starting ldap     ... done
    Starting mariadb  ... done
    Starting keycloak ... done
    Starting db       ... done
    Starting arc      ... done
  6. You may stop and delete all 5 containers by
    $ docker-compose -p dcm4chee down
    Stopping dcm4chee_arc_1      ... done
    Stopping dcm4chee_keycloak_1 ... done
    Stopping dcm4chee_ldap_1     ... done
    Stopping dcm4chee_mariadb_1  ... done
    Stopping dcm4chee_db_1       ... done
    Removing dcm4chee_arc_1      ... done
    Removing dcm4chee_keycloak_1 ... done
    Removing dcm4chee_ldap_1     ... done
    Removing dcm4chee_mariadb_1  ... done
    Removing dcm4chee_db_1       ... done
    Removing network dcm4chee_network
Clone this wiki locally