Skip to content

Commit

Permalink
added secret regeneration script into Keycloak
Browse files Browse the repository at this point in the history
  • Loading branch information
bcrickboom committed Nov 20, 2024
1 parent bac0bd9 commit 31b481c
Show file tree
Hide file tree
Showing 8 changed files with 303 additions and 19 deletions.
2 changes: 1 addition & 1 deletion minimal-setup/basic-auth/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ services:
restart: unless-stopped

orthanc-db:
image: postgres:14
image: postgres:15
restart: unless-stopped
volumes: ["orthanc-db:/var/lib/postgresql/data"]
environment:
Expand Down
12 changes: 6 additions & 6 deletions minimal-setup/keycloak-meddream-full/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ version: "3"
services:

nginx:
image: orthancteam/orthanc-nginx:24.9.0
image: orthancteam/orthanc-nginx:24.9.1
depends_on: [orthanc, orthanc-auth-service, orthanc-for-api, meddream-viewer, keycloak]
restart: unless-stopped
ports: ["80:80"]
Expand All @@ -24,7 +24,7 @@ services:
ENABLE_ORTHANC_FOR_API: "true"

orthanc:
image: orthancteam/orthanc:24.8.3
image: orthancteam/orthanc:24.10.1
volumes:
- orthanc-storage:/var/lib/orthanc/db
depends_on: [orthanc-db]
Expand Down Expand Up @@ -76,7 +76,7 @@ services:
}
orthanc-auth-service:
image: orthancteam/orthanc-auth-service:24.9.0
image: orthancteam/orthanc-auth-service:24.9.1
depends_on: [keycloak, meddream-token-service]
# permissions can be customized in the permissions.json file
volumes:
Expand Down Expand Up @@ -104,7 +104,7 @@ services:
POSTGRES_HOST_AUTH_METHOD: "trust"

keycloak:
image: orthancteam/orthanc-keycloak:24.9.0
image: orthancteam/orthanc-keycloak:24.9.1
depends_on: [keycloak-db]
restart: unless-stopped
environment:
Expand All @@ -130,7 +130,7 @@ services:
restart: unless-stopped

meddream-viewer:
image: orthancteam/meddream-viewer:24.9.0
image: orthancteam/meddream-viewer:24.9.1
restart: unless-stopped
depends_on:
- orthanc-for-api
Expand All @@ -152,7 +152,7 @@ services:

# An orthanc dedicated for API accesses and also used by MedDream
orthanc-for-api:
image: orthancteam/orthanc:24.8.3
image: orthancteam/orthanc:24.10.1
volumes:
- orthanc-storage:/var/lib/orthanc/db
- ./meddream-plugin.py:/scripts/meddream-plugin.py
Expand Down
9 changes: 6 additions & 3 deletions minimal-setup/keycloak/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ services:
ENABLE_OHIF: "true"

orthanc:
image: orthancteam/orthanc:24.8.3
#image: orthancteam/orthanc:24.8.3
image: orthancteam/orthanc-pre-release:master-unstable
volumes:
- orthanc-storage:/var/lib/orthanc/db
depends_on: [orthanc-db]
Expand Down Expand Up @@ -90,7 +91,7 @@ services:
}
orthanc-auth-service:
image: orthancteam/orthanc-auth-service:24.9.0
image: orthancteam/orthanc-auth-service:main
# always disable port mapping in production !!!
# ports: ["8000:8000"]
# permissions can be customized in the permissions.json file
Expand All @@ -104,7 +105,7 @@ services:
# ENABLE_KEYCLOAK_API_KEYS: "true"
# # to enable the permissions edition UI in OE2, you need to provide a KEYCLOAK_CLIENT_SECRET
# KEYCLOAK_CLIENT_SECRET: "change-me-I-am-a-secret-you-get-in-keycloak-admin-ui"
KEYCLOAK_CLIENT_SECRET: "TxOYLTicpl1iZIO0XgWzSE0jzmA40mb5"
KEYCLOAK_CLIENT_SECRET: "BW4jmAQXmnegXXDXKy7SPuStxSoPSG7M"
PUBLIC_ORTHANC_ROOT: "http://localhost/orthanc/"
PUBLIC_LANDING_ROOT: "http://localhost/orthanc/ui/app/token-landing.html"
# to use OHIF-plugin: make sure to use http://localhost/orthanc/ohif/
Expand Down Expand Up @@ -143,6 +144,8 @@ services:
KC_DB_USERNAME: "keycloak"
KC_DB_PASSWORD: "keycloak"
# KC_HOSTNAME: "https://mydomain.com/keycloak"
# volumes:
# - /home/bc/tmp:/usr/tmp

keycloak-db:
image: postgres:14
Expand Down
11 changes: 8 additions & 3 deletions sources/keycloak/Dockerfile.orthanc-keycloak
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ FROM quay.io/keycloak/keycloak:25.0.5
COPY --from=builder /opt/keycloak/ /opt/keycloak/

COPY keycloak/realm-export.json /opt/keycloak/data/import/
COPY keycloak/regenerate-client-secret.sh /opt/keycloak/bin/
COPY keycloak/entrypoint.sh /opt/keycloak/bin/

ENV KC_HOSTNAME=http://localhost/keycloak

ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
CMD ["start", "--optimized", "--import-realm", "--http-enabled", "true", "--proxy-headers", "xforwarded"]
#ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
#CMD ["start", "--optimized", "--import-realm", "--http-enabled", "true", "--proxy-headers", "xforwarded"]
ENTRYPOINT ["/opt/keycloak/bin/entrypoint.sh"]

# to play with UI/themes/css:
#CMD ["start", "--optimized", "--import-realm", "--http-enabled", "true", "--spi-theme-static-max-age=-1", "--spi-theme-cache-themes=false", "--spi-theme-cache-templates=false"]
Expand All @@ -35,9 +38,11 @@ CMD ["start", "--optimized", "--import-realm", "--http-enabled", "true", "--prox
# - bind a volume to /usr/tmp (copose file)
# - replace the last "CMD" command of current Docker file by the following one:
# CMD ["export --file /usr/tmp/realm-export.json --realm orthanc"]
# - rebuild the keycloak image (adapt path for files to copy in current file: lines 13 and 20)
# - rebuild the keycloak image from the folder 'sources' with this command:
# `docker build --file keycloak/Dockerfile.orthanc-keycloak --tag kc-temp .`
# - start your setup
# - then keycloak will start, export the realm and exit. From that moment, your realm
# (including users, roles, clients,...) will be available in the /usr/tmp/realm-export.json
# - don't forget to restore compose and current file


10 changes: 10 additions & 0 deletions sources/keycloak/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

# let's begin 2 tasks:
# the first task waits the Keycloak readyness to generate and print the Keycloak client secret
# the second task is the default entry point of Keycloak
# the first task will be started in background (thanks to the '&'), so the second task will start at the same time
cd /opt/keycloak/bin/
./regenerate-client-secret.sh &
./kc.sh start --optimized --import-realm --http-enabled true --proxy-headers xforwarded

85 changes: 79 additions & 6 deletions sources/keycloak/realm-export.json
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,23 @@
"realmRoles" : [ "external-role", "default-roles-orthanc" ],
"notBefore" : 0,
"groups" : [ ]
}, {
"id" : "35704d57-da75-4d73-81f4-85cd605398f4",
"username" : "service-account-admin-cli",
"emailVerified" : false,
"createdTimestamp" : 1732096845374,
"enabled" : true,
"totp" : false,
"serviceAccountClientId" : "admin-cli",
"credentials" : [ ],
"disableableCredentialTypes" : [ ],
"requiredActions" : [ ],
"realmRoles" : [ "default-roles-orthanc" ],
"clientRoles" : {
"realm-management" : [ "view-users", "manage-users", "manage-clients" ]
},
"notBefore" : 0,
"groups" : [ ]
} ],
"scopeMappings" : [ {
"clientScope" : "offline_access",
Expand Down Expand Up @@ -552,10 +569,15 @@
"id" : "74a99b9d-221a-4dd1-9ba4-ec4f249c3e0a",
"clientId" : "admin-cli",
"name" : "${client_admin-cli}",
"description" : "",
"rootUrl" : "",
"adminUrl" : "",
"baseUrl" : "",
"surrogateAuthRequired" : false,
"enabled" : true,
"alwaysDisplayInConsole" : false,
"clientAuthenticatorType" : "client-secret",
"secret" : "NPtsEUenl6nw8gJmM886TbvzuGPzvgt9",
"redirectUris" : [ ],
"webOrigins" : [ ],
"notBefore" : 0,
Expand All @@ -564,16 +586,66 @@
"standardFlowEnabled" : false,
"implicitFlowEnabled" : false,
"directAccessGrantsEnabled" : true,
"serviceAccountsEnabled" : false,
"publicClient" : true,
"serviceAccountsEnabled" : true,
"publicClient" : false,
"frontchannelLogout" : false,
"protocol" : "openid-connect",
"attributes" : {
"post.logout.redirect.uris" : "+"
"oidc.ciba.grant.enabled" : "false",
"client.secret.creation.time" : "1732096845",
"backchannel.logout.session.required" : "true",
"post.logout.redirect.uris" : "+",
"display.on.consent.screen" : "false",
"oauth2.device.authorization.grant.enabled" : "false",
"use.jwks.url" : "false",
"backchannel.logout.revoke.offline.tokens" : "false"
},
"authenticationFlowBindingOverrides" : { },
"fullScopeAllowed" : false,
"nodeReRegistrationTimeout" : 0,
"protocolMappers" : [ {
"id" : "d169bc7b-c8b3-4e57-b0f8-153d9e0842a3",
"name" : "Client Host",
"protocol" : "openid-connect",
"protocolMapper" : "oidc-usersessionmodel-note-mapper",
"consentRequired" : false,
"config" : {
"user.session.note" : "clientHost",
"id.token.claim" : "true",
"introspection.token.claim" : "true",
"access.token.claim" : "true",
"claim.name" : "clientHost",
"jsonType.label" : "String"
}
}, {
"id" : "14c88af5-f584-4eba-ab17-2ea10d5060ae",
"name" : "Client IP Address",
"protocol" : "openid-connect",
"protocolMapper" : "oidc-usersessionmodel-note-mapper",
"consentRequired" : false,
"config" : {
"user.session.note" : "clientAddress",
"id.token.claim" : "true",
"introspection.token.claim" : "true",
"access.token.claim" : "true",
"claim.name" : "clientAddress",
"jsonType.label" : "String"
}
}, {
"id" : "cb2eee45-a7be-49b5-afe5-8f997b80b353",
"name" : "Client ID",
"protocol" : "openid-connect",
"protocolMapper" : "oidc-usersessionmodel-note-mapper",
"consentRequired" : false,
"config" : {
"user.session.note" : "client_id",
"id.token.claim" : "true",
"introspection.token.claim" : "true",
"access.token.claim" : "true",
"claim.name" : "client_id",
"jsonType.label" : "String"
}
} ],
"defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ],
"optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
}, {
Expand Down Expand Up @@ -773,8 +845,9 @@
"consentRequired" : false,
"config" : {
"user.session.note" : "AUTH_TIME",
"id.token.claim" : "true",
"introspection.token.claim" : "true",
"userinfo.token.claim" : "true",
"id.token.claim" : "true",
"access.token.claim" : "true",
"claim.name" : "auth_time",
"jsonType.label" : "long"
Expand Down Expand Up @@ -1262,7 +1335,7 @@
"subType" : "authenticated",
"subComponents" : { },
"config" : {
"allowed-protocol-mapper-types" : [ "oidc-address-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "oidc-full-name-mapper" ]
"allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-address-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper" ]
}
}, {
"id" : "7861a143-5c23-448d-8db7-59b4443587cc",
Expand All @@ -1287,7 +1360,7 @@
"subType" : "anonymous",
"subComponents" : { },
"config" : {
"allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-property-mapper", "oidc-full-name-mapper" ]
"allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "saml-role-list-mapper" ]
}
}, {
"id" : "224bd8df-9b3c-4e5f-9373-0182a443eba3",
Expand Down
101 changes: 101 additions & 0 deletions sources/keycloak/regenerate-client-secret.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/bin/bash

##########################################################################

# ## Goal

# This script will replace the 'admin-cli' client default secret by
# a freshly generated one and then print it in the logs.

# In the second part of the script, the permissions needed to regenerate
# this secret will be removed.

# ## Usage

# This script is not intended to be ran manually, but it is executed
# during the Keycloak boot sequence and will regenerate the new
# secret only if the read value is the default one.

# ## Notes

# This script being executed to avoid a remaining default secret,
# all the ids needed in the commands are hardcoded.
# It would be more elegant to use grep and other bash tools to parse
# the json answers, but this will be done only if really needed (feel
# the pain as one says).

##########################################################################

cd /opt/keycloak/bin/

# wait till Keycloak is ready

READY=0

while [ $READY -eq 0 ]; do
# Try to authenticate and capture response
RESPONSE=$(./kcadm.sh config credentials --server http://localhost:8080 --realm orthanc --client admin-cli --secret NPtsEUenl6nw8gJmM886TbvzuGPzvgt9 2>&1)

# Wait till Keycloak is ready
echo "$RESPONSE" | grep -q "Connection refused"
if [ $? -eq 0 ]; then
echo "### Keycloak is not ready (Connection refused). Retrying..."
sleep 3
continue
fi

# If 'Invalid' is part of the response, the secret is already regenerated, so exit
echo "$RESPONSE" | grep -q "Invalid"
if [ $? -eq 0 ]; then
echo "### Access denied with the default secret, probably already regenerated. Exiting script..."
exit 0
else
echo "### Keycloak is ready, script authenticated..."
READY=1
fi
done

# from here, some lines are commented out (###)
# indeed, as explained above, everything is hardcoded for simplicity purposes
# but if there is a need to improve the script or to get new ids, the logic is here...

# get 'admin-cli' client id:
###./kcadm.sh get clients -r orthanc --fields clientId,id

# regenerate the secret
RESPONSE=$(./kcadm.sh create clients/74a99b9d-221a-4dd1-9ba4-ec4f249c3e0a/client-secret -r orthanc 2>&1)

# if 'error' is part of the response, there is a problem, so warning message
if [[ "$RESPONSE" == *"error"* ]]; then
echo "### ERROR! Unable to regenerate the secret, maybe some missing permissions..."
fi

# get this new secret
RESPONSE=$(./kcadm.sh get clients/74a99b9d-221a-4dd1-9ba4-ec4f249c3e0a/client-secret -r orthanc 2>&1)

# print the secret
echo -e "\n##########################################################################################"
echo -e "Here is the secret to use for the KEYCLOAK_CLIENT_SECRET env var in the auth service:"
echo -e "$RESPONSE" | grep -o '"value" : "[^"]*"' | sed 's/"value" : "\(.*\)"/\1/'
echo -e "##########################################################################################\n"

# get service account user (a kind of account behind the account)
###./kcadm.sh get clients/74a99b9d-221a-4dd1-9ba4-ec4f249c3e0a/service-account-user -r orthanc

# get roles for this account user
###./kcadm.sh get users/35704d57-da75-4d73-81f4-85cd605398f4/role-mappings -r orthanc

# get clientMapping only
###./kcadm.sh get users/35704d57-da75-4d73-81f4-85cd605398f4/role-mappings/clients/34c7489b-ad3c-4483-a523-e578c1c6dc45 -r orthanc

# remove permission manage-clients
RESPONSE=$(./kcadm.sh delete users/35704d57-da75-4d73-81f4-85cd605398f4/role-mappings/clients/34c7489b-ad3c-4483-a523-e578c1c6dc45 -r orthanc -b '[{"id": "f1360e68-78d5-4df1-a7f9-de0db0de8eb7", "name": "manage-clients"}, {"id": "098dc91c-18f2-4b22-a522-cf5ed10315a5", "name": "manage-users"}]' 2>&1)

# error case
if [ ${#RESPONSE} -ne 0 ]; then
echo -e "\n\n##### WARNING ! WARNING ! WARNING !"
echo -e "\n##### Unable to remove the permissions! Keycloak shoulnd t be used as it is!!\n\n"
exit 1
fi

exit 0
Loading

0 comments on commit 31b481c

Please sign in to comment.