Skip to content

Commit

Permalink
fix(docker-jans-saml): unable to access KC admin console from browser (
Browse files Browse the repository at this point in the history
…#7336)

* fix(docker-jans-saml): unable to access KC admin console from browser

Signed-off-by: iromli <isman.firmansyah@gmail.com>

* chore(docker-jans-saml): generate defaults KC credentials

Signed-off-by: iromli <isman.firmansyah@gmail.com>

---------

Signed-off-by: iromli <isman.firmansyah@gmail.com>
Co-authored-by: Mohammad Abudayyeh <47318409+moabu@users.noreply.github.com>
  • Loading branch information
iromli and moabu committed Jan 11, 2024
1 parent 0152c24 commit ba2c0a3
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 41 deletions.
11 changes: 6 additions & 5 deletions docker-jans-saml/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -161,17 +161,18 @@ ENV CN_MAX_RAM_PERCENTAGE=75.0 \
CN_AWS_SECRETS_ENDPOINT_URL="" \
CN_AWS_SECRETS_PREFIX=jans \
CN_AWS_SECRETS_REPLICA_FILE="" \
CN_SAML_PORT=8083 \
CN_SAML_HOST=0.0.0.0 \
CN_SAML_HTTP_PORT=8083 \
CN_SAML_HTTP_HOST=0.0.0.0 \
CN_SAML_JAVA_OPTIONS="" \
KC_HEALTH_ENABLED=true
# KC_METRICS_ENABLED=true
CN_SAML_KC_CREDENTIALS_FILE=/etc/jans/conf/kc_admin_creds \
KC_HEALTH_ENABLED=true \
KC_METRICS_ENABLED=true

# ==========
# misc stuff
# ==========

EXPOSE $CN_SAML_PORT
EXPOSE $CN_SAML_HTTP_PORT

LABEL org.opencontainers.image.url="ghcr.io/janssenproject/jans/saml" \
org.opencontainers.image.authors="Janssen Project <support@jans.io>" \
Expand Down
13 changes: 6 additions & 7 deletions docker-jans-saml/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ The following environment variables are supported by the container:
- `CN_COUCHBASE_KEEPALIVE_INTERVAL`: Keep-alive interval for Couchbase connection (default to `30000` milliseconds).
- `CN_COUCHBASE_KEEPALIVE_TIMEOUT`: Keep-alive timeout for Couchbase connection (default to `2500` milliseconds).
- `CN_SAML_JAVA_OPTIONS`: Java options passed to entrypoint, i.e. `-Xmx1024m` (default to empty-string).
- `CN_SAML_KC_CREDENTIALS_FILE`: File contains credentials for Keycloak admin user.
- `GOOGLE_APPLICATION_CREDENTIALS`: Optional JSON file (contains Google credentials) that can be injected into container for authentication. Refer to https://cloud.google.com/docs/authentication/provide-credentials-adc#how-to for supported credentials.
- `GOOGLE_PROJECT_ID`: ID of Google project.
- `CN_GOOGLE_SECRET_VERSION_ID`: Janssen secret version ID in Google Secret Manager. Defaults to `latest`, which is recommended.
Expand Down Expand Up @@ -117,18 +118,16 @@ As per v1.0.1, hybrid persistence supports all available persistence types. To c
}
```

### Keycloak Admin Credentials
### Keycloak Administration

Admin credentials are set in `/etc/jans/conf/kc_admin_creds` with the following format:
#### Admin Credentials

```
BASE64(username:password)
```
By defaults, Keycloak's admin username and password are self-generated during first install and saved as `kc_admin_username` (in configs layer) and `kc_admin_password` (in secrets layer) respectively.

Example:
The credentials will be rendered as `/etc/jans/conf/kc_admin_creds` file (can be changed via `CN_SAML_KC_CREDENTIALS_FILE` environment variable) with the following format:

```
echo admin:admin | base64 -w0 > /etc/jans/conf/kc_admin_creds
BASE64(username:password)
```

The credentials will be exported as `KEYCLOAK_ADMIN` and `KEYCLOAK_ADMIN_PASSWORD` environment variables for initial admin username and password.
30 changes: 29 additions & 1 deletion docker-jans-saml/scripts/bootstrap.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import base64
import logging.config
import os
import typing as _t
Expand Down Expand Up @@ -33,9 +34,13 @@

def render_keycloak_conf(ctx):
with open("/app/templates/jans-saml/keycloak.conf") as f:
tmpl = f.read()
defaults = f.read()

with open("/app/templates/jans-saml/keycloak.extra.conf") as f:
extras = f.read()

with open("/opt/keycloak/conf/keycloak.conf", "w") as f:
tmpl = "\n".join([defaults, extras])
f.write(tmpl % ctx)


Expand All @@ -44,6 +49,7 @@ def main():
persistence_setup = PersistenceSetup(manager)
persistence_setup.import_ldif_files()
render_keycloak_conf(persistence_setup.ctx)
render_keycloak_creds()


class PersistenceSetup:
Expand Down Expand Up @@ -116,6 +122,17 @@ def ctx(self) -> dict[str, _t.Any]:
).decode()
self.manager.secret.set("saml_scim_client_encoded_pw", ctx["saml_scim_client_encoded_pw"])

# keycloak credentials
ctx["kc_admin_username"] = self.manager.config.get("kc_admin_username")
if not ctx["kc_admin_username"]:
ctx["kc_admin_username"] = "admin"
self.manager.config.set("kc_admin_username", ctx["kc_admin_username"])

ctx["kc_admin_password"] = self.manager.secret.get("kc_admin_password")
if not ctx["kc_admin_password"]:
ctx["kc_admin_password"] = get_random_chars()
self.manager.secret.set("kc_admin_password", ctx["kc_admin_password"])

# finalized ctx
return ctx

Expand All @@ -132,5 +149,16 @@ def import_ldif_files(self) -> None:
self.client.create_from_ldif(file_, self.ctx)


def render_keycloak_creds():
creds_file = os.environ.get("CN_SAML_KC_CREDENTIALS_FILE", "/etc/jans/conf/kc_admin_creds")

if not os.path.isfile(creds_file):
with open(creds_file, "w") as f:
username = manager.config.get("kc_admin_username")
password = manager.secret.get("kc_admin_password")
creds_bytes = f"{username}:{password}".encode()
f.write(base64.b64encode(creds_bytes).decode())


if __name__ == "__main__":
main()
16 changes: 7 additions & 9 deletions docker-jans-saml/scripts/configure_kc.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ def __init__(self, admin_username, admin_password, base_dir, ctx):

@property
def server_url(self):
host = os.environ.get("CN_SAML_HOST", "0.0.0.0") # nosec: B104
port = os.environ.get("CN_SAML_PORT", "8083")
host = os.environ.get("CN_SAML_HTTP_HOST", "0.0.0.0") # nosec: B104
port = os.environ.get("CN_SAML_HTT_PORT", "8083")
return f"http://{host}:{port}/kc"

@property
Expand Down Expand Up @@ -172,13 +172,11 @@ def create_user(self):
def main():
manager = get_manager()

if os.path.isfile("/etc/jans/conf/kc_admin_creds"):
with open("/etc/jans/conf/kc_admin_creds") as f:
creds = f.read().strip()
admin_username, admin_password = base64.b64decode(creds).decode().strip().split(":")
else:
admin_username = os.environ.get("KEYCLOAK_ADMIN", "")
admin_password = os.environ.get("KEYCLOAK_ADMIN_PASSWORD", "")
creds_file = os.environ.get("CN_SAML_KC_CREDENTIALS_FILE", "/etc/jans/conf/kc_admin_creds")

with open(creds_file) as f:
creds = f.read().strip()
admin_username, admin_password = base64.b64decode(creds).decode().strip().split(":")

ctx = {
"jans_idp_realm": "jans-api",
Expand Down
27 changes: 10 additions & 17 deletions docker-jans-saml/scripts/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,19 @@ get_max_ram_percentage() {
}

export_keycloak_admin_creds() {
if [ -f /etc/jans/conf/kc_admin_creds ]; then
creds="$(base64 -d < /etc/jans/conf/kc_admin_creds)"
admin_username=$(echo "$creds" | awk -F ":" '{print $1}')
admin_password=$(echo "$creds" | awk -F ":" '{print $2}')
else
admin_username=${KEYCLOAK_ADMIN:-}
admin_password=${KEYCLOAK_ADMIN_PASSWORD:-}
fi
creds_file=${CN_SAML_KC_CREDENTIALS_FILE:-/etc/jans/conf/kc_admin_creds}
creds="$(base64 -d < ${creds_file})"
admin_username=$(echo "$creds" | awk -F ":" '{print $1}')
admin_password=$(echo "$creds" | awk -F ":" '{print $2}')
export KEYCLOAK_ADMIN="$admin_username"
export KEYCLOAK_ADMIN_PASSWORD="$admin_password"
}

export_keycloak_admin_creds
python3 "$basedir/wait.py"
python3 "$basedir/bootstrap.py"
python3 "$basedir/configure_kc.py" &
python3 "$basedir/upgrade.py"
export_keycloak_admin_creds

java_opts="$(get_max_ram_percentage) $(get_java_options)"
export JAVA_OPTS_APPEND="$java_opts"
Expand All @@ -46,19 +42,16 @@ export JAVA_OPTS_APPEND="$java_opts"
exec /opt/keycloak/bin/kc.sh start \
-Dlog.base=/opt/keycloak/logs/ \
-Djans.config.prop.path=/opt/keycloak/providers \
--health-enabled=true \
--metrics-enabled=true \
--http-host="${CN_SAML_HOST}" \
--http-port="${CN_SAML_PORT}" \
--http-host="${CN_SAML_HTTP_HOST}" \
--http-port=${CN_SAML_HTTP_PORT} \
--http-enabled=true \
--http-relative-path=/kc \
--hostname="localhost" \
--hostname-admin="localhost" \
--hostname-path=/kc \
--hostname-strict-https=false \
--hostname-strict-https=true \
--log=console \
--log-console-format='jans-saml - %d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n' \
--log-file=/opt/keycloak/logs/keycloak.log \
--log-level=INFO
--log-level=INFO \
--proxy=edge
# --db=dev-mem \
# --optimized
4 changes: 2 additions & 2 deletions docker-jans-saml/scripts/healthcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@


def run_healthcheck():
host = os.environ.get("CN_SAML_HOST", "0.0.0.0") # nosec: B104
port = os.environ.get("CN_SAML_PORT", "8083")
host = os.environ.get("CN_SAML_HTTP_HOST", "0.0.0.0") # nosec: B104
port = os.environ.get("CN_SAML_HTTP_PORT", "8083")
req = requests.get(f"http://{host}:{port}/kc/health", timeout=5)
if not req.ok:
return False
Expand Down
2 changes: 2 additions & 0 deletions docker-jans-saml/templates/jans-saml/keycloak.extra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
hostname=%(hostname)s
hostname-admin=%(hostname)s

0 comments on commit ba2c0a3

Please sign in to comment.