From 13d7fa1c8fbb9cf5d8b7f18610335533c1f499e6 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Fri, 27 Dec 2024 20:01:56 +1100 Subject: [PATCH 1/4] chore: update keycloak to version 26 --- Makefile | 52 +++++++++++++++---- services/api/package.json | 2 +- services/keycloak/Dockerfile | 6 +-- services/keycloak/custom-mapper/pom.xml | 8 +-- .../default-keycloak-entrypoint.sh | 5 ++ services/keycloak/entrypoints/kc-startup.sh | 8 ++- yarn.lock | 18 +++---- 7 files changed, 71 insertions(+), 28 deletions(-) diff --git a/Makefile b/Makefile index 7dfb0e3e2c..72cbdad965 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,22 @@ UPSTREAM_TAG ?= latest # edge is the most current merged change BUILD_DEPLOY_IMAGE_TAG ?= edge +# UI_IMAGE_REPO and UI_IMAGE_TAG are an easy way to override the UI image used +# UI_IMAGE_REPO = uselagoon/ui +UI_IMAGE_TAG = pr-307 + +# SSHPORTALAPI_IMAGE_REPO and SSHPORTALAPI_IMAGE_TAG are an easy way to override the ssh portal api image used in the local stack lagoon-core +SSHPORTALAPI_IMAGE_REPO = shreddedbacon/ssh-portal-api +SSHPORTALAPI_IMAGE_TAG = latest + +# SSHTOKEN_IMAGE_REPO and SSHTOKEN_IMAGE_TAG are an easy way to override the ssh token image used in the local stack lagoon-core +SSHTOKEN_IMAGE_REPO = shreddedbacon/ssh-token +SSHTOKEN_IMAGE_TAG = latest + +# SSHPORTAL_IMAGE_REPO and SSHPORTAL_IMAGE_TAG are an easy way to override the ssh portal image used in the local stack lagoon-remote +# SSHPORTAL_IMAGE_REPO = +# SSHPORTAL_IMAGE_TAG = + # OVERRIDE_BUILD_DEPLOY_CONTROLLER_IMAGETAG and OVERRIDE_BUILD_DEPLOY_CONTROLLER_IMAGE_REPOSITORY # set this to a particular build image if required, defaults to nothing to consume what the chart provides OVERRIDE_BUILD_DEPLOY_CONTROLLER_IMAGETAG= @@ -354,11 +370,14 @@ logs: # Start all Lagoon Services up: ifeq ($(ARCH), darwin) - IMAGE_REPO=$(CI_BUILD_TAG) docker compose -p $(CI_BUILD_TAG) -f docker-compose.yaml -f docker-compose.local-dev.yaml --compatibility up -d + UI_IMAGE_TAG=$(UI_IMAGE_TAG) UI_IMAGE_REPO=$(UI_IMAGE_REPO) \ + IMAGE_REPO=$(CI_BUILD_TAG) docker compose -p $(CI_BUILD_TAG) \ + -f docker-compose.yaml -f docker-compose.local-dev.yaml --compatibility up -d else # once this docker issue is fixed we may be able to do away with this # linux-specific workaround: https://github.com/docker/cli/issues/2290 KEYCLOAK_URL=$$(docker network inspect -f '{{(index .IPAM.Config 0).Gateway}}' bridge):8088 \ + UI_IMAGE_TAG=$(UI_IMAGE_TAG) UI_IMAGE_REPO=$(UI_IMAGE_REPO) \ IMAGE_REPO=$(CI_BUILD_TAG) \ docker compose -p $(CI_BUILD_TAG) -f docker-compose.yaml -f docker-compose.local-dev.yaml --compatibility up -d endif @@ -388,21 +407,28 @@ local-dev-yarn-stop: .PHONY: ui-development ui-development: build-ui-logs-development - IMAGE_REPO=$(CI_BUILD_TAG) docker compose -p $(CI_BUILD_TAG) -f docker-compose.yaml -f docker-compose.local-dev.yaml --compatibility up -d api api-db api-sidecar-handler local-api-data-watcher-pusher ui keycloak keycloak-db broker api-redis + UI_IMAGE_TAG=$(UI_IMAGE_TAG) UI_IMAGE_REPO=$(UI_IMAGE_REPO) \ + IMAGE_REPO=$(CI_BUILD_TAG) docker compose -p $(CI_BUILD_TAG) \ + -f docker-compose.yaml -f docker-compose.local-dev.yaml --compatibility up -d api api-db api-sidecar-handler local-api-data-watcher-pusher ui keycloak keycloak-db broker api-redis $(MAKE) wait-for-keycloak .PHONY: api-development api-development: build-ui-logs-development - IMAGE_REPO=$(CI_BUILD_TAG) docker compose -p $(CI_BUILD_TAG) -f docker-compose.yaml -f docker-compose.local-dev.yaml --compatibility up -d api api-db api-sidecar-handler local-api-data-watcher-pusher keycloak keycloak-db broker api-redis + UI_IMAGE_TAG=$(UI_IMAGE_TAG) UI_IMAGE_REPO=$(UI_IMAGE_REPO) \ + IMAGE_REPO=$(CI_BUILD_TAG) docker compose -p $(CI_BUILD_TAG) \ + -f docker-compose.yaml -f docker-compose.local-dev.yaml --compatibility up -d api api-db api-sidecar-handler local-api-data-watcher-pusher keycloak keycloak-db broker api-redis $(MAKE) wait-for-keycloak .PHONY: ui-logs-development ui-logs-development: build-ui-logs-development - IMAGE_REPO=$(CI_BUILD_TAG) COMPOSE_STACK_NAME=$(CI_BUILD_TAG) ADDITIONAL_FLAGS="-f docker-compose.yaml -f docker-compose.local-dev.yaml" ADDITIONAL_SERVICES="ui" $(MAKE) compose-api-logs-development + UI_IMAGE_TAG=$(UI_IMAGE_TAG) UI_IMAGE_REPO=$(UI_IMAGE_REPO) \ + IMAGE_REPO=$(CI_BUILD_TAG) COMPOSE_STACK_NAME=$(CI_BUILD_TAG) \ + ADDITIONAL_FLAGS="-f docker-compose.yaml -f docker-compose.local-dev.yaml" ADDITIONAL_SERVICES="ui" $(MAKE) compose-api-logs-development .PHONY: api-logs-development api-logs-development: build-ui-logs-development - IMAGE_REPO=$(CI_BUILD_TAG) COMPOSE_STACK_NAME=$(CI_BUILD_TAG) ADDITIONAL_FLAGS="-f docker-compose.yaml -f docker-compose.local-dev.yaml" ADDITIONAL_SERVICES="" $(MAKE) compose-api-logs-development + IMAGE_REPO=$(CI_BUILD_TAG) COMPOSE_STACK_NAME=$(CI_BUILD_TAG) \ + ADDITIONAL_FLAGS="-f docker-compose.yaml -f docker-compose.local-dev.yaml" ADDITIONAL_SERVICES="" $(MAKE) compose-api-logs-development # compose-api-logs-development can be consumed by other repositories to start a local api # supported make variable passthrough are @@ -412,7 +438,9 @@ api-logs-development: build-ui-logs-development # ADDITIONAL_SERVICES - a way to pass through additional services ("ui", "ui ssh", etc..) .PHONY: compose-api-logs-development compose-api-logs-development: - docker compose -p $(COMPOSE_STACK_NAME) $(ADDITIONAL_FLAGS) --compatibility up -d $(ADDITIONAL_SERVICES) api api-db api-sidecar-handler actions-handler local-api-data-watcher-pusher keycloak keycloak-db broker api-redis logs2notifications local-minio mailhog + docker compose -p $(COMPOSE_STACK_NAME) $(ADDITIONAL_FLAGS) \ + --compatibility up -d $(ADDITIONAL_SERVICES) api api-db api-sidecar-handler actions-handler \ + local-api-data-watcher-pusher keycloak keycloak-db broker api-redis logs2notifications local-minio mailhog $(MAKE) CI_BUILD_TAG=$(COMPOSE_STACK_NAME) wait-for-keycloak ## CI targets @@ -425,7 +453,7 @@ STERN_VERSION = v2.6.1 CHART_TESTING_VERSION = v3.11.0 K3D_IMAGE = docker.io/rancher/k3s:v1.31.1-k3s1 TESTS = [nginx,api,features-kubernetes,bulk-deployment,features-kubernetes-2,features-variables,active-standby-kubernetes,tasks,drush,python,gitlab,github,bitbucket,services,workflows] -CHARTS_TREEISH = main +CHARTS_TREEISH = keycloak-tls-updates CHARTS_REPOSITORY = https://github.com/uselagoon/lagoon-charts.git #CHARTS_REPOSITORY = ../lagoon-charts TASK_IMAGES = task-activestandby @@ -725,6 +753,10 @@ endif INSTALL_LAGOON_DEPENDENCIES=false DOCKER_NETWORK=$(DOCKER_NETWORK) \ TESTS=$(TESTS) IMAGE_TAG=$(SAFE_BRANCH_NAME) DISABLE_CORE_HARBOR=true \ HELM=$(HELM) KUBECTL=$(KUBECTL) JQ=$(JQ) \ + UI_IMAGE_REPO=$(UI_IMAGE_REPO) UI_IMAGE_TAG=$(UI_IMAGE_TAG) \ + SSHPORTALAPI_IMAGE_REPO=$(SSHPORTALAPI_IMAGE_REPO) SSHPORTALAPI_IMAGE_TAG=$(SSHPORTALAPI_IMAGE_TAG) \ + SSHTOKEN_IMAGE_REPO=$(SSHTOKEN_IMAGE_REPO) SSHTOKEN_IMAGE_TAG=$(SSHTOKEN_IMAGE_TAG) \ + SSHPORTAL_IMAGE_REPO=$(SSHPORTAL_IMAGE_REPO) SSHPORTAL_IMAGE_TAG=$(SSHPORTAL_IMAGE_TAG) \ OVERRIDE_BUILD_DEPLOY_DIND_IMAGE=uselagoon/build-deploy-image:${BUILD_DEPLOY_IMAGE_TAG} \ $$([ $(OVERRIDE_BUILD_DEPLOY_CONTROLLER_IMAGETAG) ] && echo 'OVERRIDE_BUILD_DEPLOY_CONTROLLER_IMAGETAG=$(OVERRIDE_BUILD_DEPLOY_CONTROLLER_IMAGETAG)') \ $$([ $(OVERRIDE_BUILD_DEPLOY_CONTROLLER_IMAGE_REPOSITORY) ] && echo 'OVERRIDE_BUILD_DEPLOY_CONTROLLER_IMAGE_REPOSITORY=$(OVERRIDE_BUILD_DEPLOY_CONTROLLER_IMAGE_REPOSITORY)') \ @@ -822,8 +854,8 @@ k3d/push-images: k3d/get-lagoon-details: @export KUBECONFIG="$$(realpath ./kubeconfig.k3d.$(CI_BUILD_TAG))" && \ echo "===============================" && \ - echo "Lagoon UI URL: http://lagoon-ui.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io" \ - && echo "Lagoon API URL: http://lagoon-api.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io/graphql" \ + echo "Lagoon UI URL: https://lagoon-ui.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io" \ + && echo "Lagoon API URL: https://lagoon-api.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io/graphql" \ && echo "Lagoon API admin legacy token: $$(docker run \ -e JWTSECRET="$$($(KUBECTL) get secret -n lagoon-core lagoon-core-secrets -o jsonpath="{.data.JWTSECRET}" | base64 --decode)" \ -e JWTAUDIENCE=api.dev \ @@ -834,7 +866,7 @@ k3d/get-lagoon-details: && echo "SSH Core Service: lagoon-ssh.$$($(KUBECTL) -n lagoon-core get services lagoon-core-ssh -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io:$$($(KUBECTL) -n lagoon-core get services lagoon-core-ssh -o jsonpath='{.spec.ports[0].port}')" \ && echo "SSH Portal Service: lagoon-ssh-portal.$$($(KUBECTL) -n lagoon get services lagoon-remote-ssh-portal -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io:$$($(KUBECTL) -n lagoon get services lagoon-remote-ssh-portal -o jsonpath='{.spec.ports[0].port}')" \ && echo "SSH Token Service: lagoon-token.$$($(KUBECTL) -n lagoon-core get services lagoon-core-ssh-token -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io:$$($(KUBECTL) -n lagoon-core get services lagoon-core-ssh-token -o jsonpath='{.spec.ports[0].port}')" \ - && echo "Keycloak admin URL: http://lagoon-keycloak.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io/auth" \ + && echo "Keycloak admin URL: https://lagoon-keycloak.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io/auth" \ && echo "Keycloak admin password: $$($(KUBECTL) get secret -n lagoon-core lagoon-core-keycloak -o jsonpath="{.data.KEYCLOAK_ADMIN_PASSWORD}" | base64 --decode)" \ && echo "MailPit (email catching service): http://mailpit.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io" \ && echo "" \ diff --git a/services/api/package.json b/services/api/package.json index ec9d10ebca..6ba9ed01ac 100644 --- a/services/api/package.json +++ b/services/api/package.json @@ -22,7 +22,7 @@ "license": "MIT", "dependencies": { "@lagoon/commons": "4.0.0", - "@s3pweb/keycloak-admin-client-cjs": "^25.0.2", + "@s3pweb/keycloak-admin-client-cjs": "^26.0.0", "@supercharge/request-ip": "^1.1.2", "apollo-server-express": "^2.14.2", "aws-sdk": "^2.378.0", diff --git a/services/keycloak/Dockerfile b/services/keycloak/Dockerfile index 5990cbca29..bc078b23ee 100644 --- a/services/keycloak/Dockerfile +++ b/services/keycloak/Dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.8.2-jdk-11 as builder +FROM maven:3.9.9-eclipse-temurin-21-alpine as builder # build the custom token mapper in builder COPY custom-mapper/. . RUN mvn clean compile package @@ -17,7 +17,7 @@ COPY javascript /tmp/lagoon-scripts RUN cd /tmp/lagoon-scripts && zip -r ../lagoon-scripts.jar * -FROM quay.io/keycloak/keycloak:24.0.5 +FROM quay.io/keycloak/keycloak:26.0.7 COPY --from=ubi-micro-build /mnt/rootfs / ARG LAGOON_VERSION @@ -89,7 +89,7 @@ COPY entrypoints/default-keycloak-entrypoint.sh /lagoon/entrypoints/99-default-k COPY startup-scripts /opt/keycloak/startup-scripts COPY themes/lagoon /opt/keycloak/themes/lagoon COPY --from=commons /tmp/lagoon-scripts.jar /opt/keycloak/providers/lagoon-scripts.jar -COPY --from=builder /target/custom-protocol-mapper-1.0.0.jar /opt/keycloak/providers/custom-protocol-mapper-1.0.0.jar +COPY --from=builder /target/custom-protocol-mapper-1.1.0.jar /opt/keycloak/providers/custom-protocol-mapper-1.1.0.jar COPY lagoon-realm-base-import.json /lagoon/seed/lagoon-realm-base-import.json diff --git a/services/keycloak/custom-mapper/pom.xml b/services/keycloak/custom-mapper/pom.xml index 9b00fba5ff..6dc866bce3 100644 --- a/services/keycloak/custom-mapper/pom.xml +++ b/services/keycloak/custom-mapper/pom.xml @@ -6,11 +6,11 @@ net.cake.keycloak.custom custom-protocol-mapper - 1.0.0 + 1.1.0 jar - 17.0.1 + 26.0.7 @@ -52,7 +52,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.7.0 + 3.13.0 true 1.8 @@ -62,7 +62,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.1.0 + 3.6.0 diff --git a/services/keycloak/entrypoints/default-keycloak-entrypoint.sh b/services/keycloak/entrypoints/default-keycloak-entrypoint.sh index ba2e12721f..ef516d12f5 100755 --- a/services/keycloak/entrypoints/default-keycloak-entrypoint.sh +++ b/services/keycloak/entrypoints/default-keycloak-entrypoint.sh @@ -15,4 +15,9 @@ export KC_HOSTNAME_ADMIN_URL=${KEYCLOAK_FRONTEND_URL} export KC_DB_POOL_MAX_SIZE=${KEYCLOAK_DS_MAX_POOL_SIZE:-20} export KC_DB_POOL_MIN_SIZE=${KEYCLOAK_DS_MIN_POOL_SIZE:-0} +# https://www.keycloak.org/docs/latest/upgrading/#admin-bootstrapping-and-recovery +# https://www.keycloak.org/server/bootstrap-admin-recovery +export KC_BOOTSTRAP_ADMIN_USERNAME=$KEYCLOAK_ADMIN_USER +export KC_BOOTSTRAP_ADMIN_PASSWORD=$KEYCLOAK_ADMIN_PASSWORD + KEYCLOAK_USER=$KEYCLOAK_ADMIN_USER KEYCLOAK_PASSWORD=$KEYCLOAK_ADMIN_PASSWORD KEYCLOAK_ADMIN=$KEYCLOAK_ADMIN_USER /lagoon/kc-startup.sh "$@" diff --git a/services/keycloak/entrypoints/kc-startup.sh b/services/keycloak/entrypoints/kc-startup.sh index 2a96ef8dc6..abb603dc54 100755 --- a/services/keycloak/entrypoints/kc-startup.sh +++ b/services/keycloak/entrypoints/kc-startup.sh @@ -6,4 +6,10 @@ shopt -s failglob /opt/keycloak/startup-scripts/00-configure-lagoon.sh & disown -/opt/keycloak/bin/kc.sh "$@" --features="scripts,token-exchange,admin-fine-grained-authz" \ No newline at end of file +# https://www.keycloak.org/docs/latest/upgrading/#new-hostname-options +# https://www.keycloak.org/server/hostname +# "--hostname-backchannel-dynamic" +# Enables dynamic resolving of backchannel URLs, including hostname, scheme, port and context path. +# Set to true if your application accesses Keycloak via a private network. If set to true, hostname option needs to be specified as a full URL. +/opt/keycloak/bin/kc.sh "$@" --features="scripts,token-exchange,admin-fine-grained-authz" \ + --hostname-backchannel-dynamic true --hostname ${KC_HOSTNAME_URL} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index e904251128..25410c012d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -703,10 +703,10 @@ resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== -"@keycloak/keycloak-admin-client@25.0.4": - version "25.0.4" - resolved "https://registry.yarnpkg.com/@keycloak/keycloak-admin-client/-/keycloak-admin-client-25.0.4.tgz#2ec46bab133cc807df78ffd7ca7bba47ec8ed000" - integrity sha512-mZVFwly7cHZq1XpvJrrOutU0qrUbGo8NUdpb7PS4309x8yG2a4/WyZfh2lgiopBRQ6R/b24RsuHa4GetQPqT+g== +"@keycloak/keycloak-admin-client@26.0.6": + version "26.0.6" + resolved "https://registry.yarnpkg.com/@keycloak/keycloak-admin-client/-/keycloak-admin-client-26.0.6.tgz#b2ac56de7f4251c8a6a938745843e98000498646" + integrity sha512-pZmaSAyg+LwQ3qnZF+01ZkURpcoEdLAloUK5KOZjE9jyNd86EHdx98/XmTYaJIuQ6ydMXxTWWc5Grq18H+PvJQ== dependencies: camelize-ts "^3.0.0" url-join "^5.0.0" @@ -926,12 +926,12 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== -"@s3pweb/keycloak-admin-client-cjs@^25.0.2": - version "25.0.4" - resolved "https://registry.yarnpkg.com/@s3pweb/keycloak-admin-client-cjs/-/keycloak-admin-client-cjs-25.0.4.tgz#925aa0f780233992e44d09a1efbfcbf4718f924a" - integrity sha512-0qQYvmftr4rZKO1JuDq077odNwQ8rS/FGlvBOSOoncvM2i7HljEHvMcsAHR3gNrOkawVlPoYwA+zZdtHICIU4A== +"@s3pweb/keycloak-admin-client-cjs@^26.0.0": + version "26.0.6" + resolved "https://registry.yarnpkg.com/@s3pweb/keycloak-admin-client-cjs/-/keycloak-admin-client-cjs-26.0.6.tgz#49b81da9980d2d3d058a616c8677d64d08a43a34" + integrity sha512-cF4SZcxj/CUK0hZ1dHmyPjVI1BcLvz7u6S8e9YUfqy7wweZScIl1/VpxPgfA9aaLCAcE6kAv++BjcQcvxzkmSg== dependencies: - "@keycloak/keycloak-admin-client" "25.0.4" + "@keycloak/keycloak-admin-client" "26.0.6" "@sinclair/typebox@^0.27.8": version "0.27.8" From d93b364cf25fa7d063da726c0b42c742ea4c5029 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Mon, 30 Dec 2024 07:21:14 +1100 Subject: [PATCH 2/4] chore: support https with flag --- .gitignore | 1 + Makefile | 78 +++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 1d9481ecbf..cc47ff336d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ local-dev/kubectl local-dev/jq local-dev/stern local-dev/go +local-dev/certificates **/v8-* node_modules/ build/* diff --git a/Makefile b/Makefile index 72cbdad965..c3864ffa16 100644 --- a/Makefile +++ b/Makefile @@ -53,18 +53,22 @@ UPSTREAM_TAG ?= latest BUILD_DEPLOY_IMAGE_TAG ?= edge # UI_IMAGE_REPO and UI_IMAGE_TAG are an easy way to override the UI image used +# only works for installations where INSTALL_STABLE_CORE=false # UI_IMAGE_REPO = uselagoon/ui UI_IMAGE_TAG = pr-307 # SSHPORTALAPI_IMAGE_REPO and SSHPORTALAPI_IMAGE_TAG are an easy way to override the ssh portal api image used in the local stack lagoon-core +# only works for installations where INSTALL_STABLE_CORE=false SSHPORTALAPI_IMAGE_REPO = shreddedbacon/ssh-portal-api SSHPORTALAPI_IMAGE_TAG = latest # SSHTOKEN_IMAGE_REPO and SSHTOKEN_IMAGE_TAG are an easy way to override the ssh token image used in the local stack lagoon-core +# only works for installations where INSTALL_STABLE_CORE=false SSHTOKEN_IMAGE_REPO = shreddedbacon/ssh-token SSHTOKEN_IMAGE_TAG = latest # SSHPORTAL_IMAGE_REPO and SSHPORTAL_IMAGE_TAG are an easy way to override the ssh portal image used in the local stack lagoon-remote +# only works for installations where INSTALL_STABLE_REMOTE=false # SSHPORTAL_IMAGE_REPO = # SSHPORTAL_IMAGE_TAG = @@ -476,6 +480,15 @@ STABLE_CORE_CHART_VERSION = STABLE_REMOTE_CHART_VERSION = STABLE_STABLE_BUILDDEPLOY_CHART_VERSION = +# older versions of lagoon core allowed insecure connections via http during testing +# keycloak 26 has required secure connections unless on localhost, which this local stack does not use +# https://www.keycloak.org/docs/latest/upgrading/#a-secure-context-is-now-required +# this means that we have to enable connections between api/keycloak/ui with https +# a new `make k3d/generate-ca` exists to facilitate the creation of a CA certificate to be used for generating ingress certificates +# once created, the certificate will exist in `local-dev/certificates` and can be installed in your browsers trusted authorities if you wish +# or used with curl `--cacert/--capath` for example +LAGOON_CORE_USE_HTTPS = true + # install mailpit for lagoon local development INSTALL_MAILPIT = true @@ -511,6 +524,15 @@ ifeq ($(MACHINE), arm64) INSTALL_UNAUTHENTICATED_REGISTRY = true endif +# if this is a stable version of lagoon that is older than the release version that keycloak 26 is used in +# then use http connections +ifeq ($(INSTALL_STABLE_CORE),true) +ifeq (,$(subst ",,$(STABLE_CORE_CHART_APP_VERSION))) + STABLE_CORE_CHART_APP_VERSION = $(shell $(HELM) search repo lagoon/lagoon-core -o json | $(JQ) -r '.[]|.app_version') +endif + LAGOON_CORE_USE_HTTPS = $(shell if ! printf 'v2.23.0\n%s\n' "$(STABLE_CORE_CHART_APP_VERSION)" | sort -V -C; then echo false; else echo true; fi) +endif + # the name of the docker network to create DOCKER_NETWORK = k3d @@ -724,13 +746,17 @@ k3d/dev: k3d/checkout-charts k3d/install-lagoon # this is used to checkout the chart repo/branch again if required. otherwise will use the symbolic link # that is created for subsequent commands +# it will also copy the certs generated for this local k3d into the checked out charts repo for re-use by the charts installer .PHONY: k3d/checkout-charts -k3d/checkout-charts: +k3d/checkout-charts: k3d/generate-ca export CHARTSDIR=$$(mktemp -d ./lagoon-charts.XXX) \ && ln -sfn "$$CHARTSDIR" lagoon-charts.k3d.lagoon \ && git clone $(CHARTS_REPOSITORY) "$$CHARTSDIR" \ && cd "$$CHARTSDIR" \ - && git checkout $(CHARTS_TREEISH) + && git checkout $(CHARTS_TREEISH) \ + && mkdir -p certs \ + && cp ../local-dev/certificates/* certs/. + # this just installs lagoon-core, lagoon-remote, and lagoon-build-deploy # doing this allows for lagoon to be installed with a known stable chart version with the INSTALL_STABLE_X overrides @@ -754,6 +780,7 @@ endif TESTS=$(TESTS) IMAGE_TAG=$(SAFE_BRANCH_NAME) DISABLE_CORE_HARBOR=true \ HELM=$(HELM) KUBECTL=$(KUBECTL) JQ=$(JQ) \ UI_IMAGE_REPO=$(UI_IMAGE_REPO) UI_IMAGE_TAG=$(UI_IMAGE_TAG) \ + LAGOON_CORE_USE_HTTPS=$(LAGOON_CORE_USE_HTTPS) \ SSHPORTALAPI_IMAGE_REPO=$(SSHPORTALAPI_IMAGE_REPO) SSHPORTALAPI_IMAGE_TAG=$(SSHPORTALAPI_IMAGE_TAG) \ SSHTOKEN_IMAGE_REPO=$(SSHTOKEN_IMAGE_REPO) SSHTOKEN_IMAGE_TAG=$(SSHTOKEN_IMAGE_TAG) \ SSHPORTAL_IMAGE_REPO=$(SSHPORTAL_IMAGE_REPO) SSHPORTAL_IMAGE_TAG=$(SSHPORTAL_IMAGE_TAG) \ @@ -780,6 +807,9 @@ endif $$([ $(INSTALL_MARIADB_PROVIDER) ] && echo 'INSTALL_MARIADB_PROVIDER=$(INSTALL_MARIADB_PROVIDER)') \ $$([ $(INSTALL_POSTGRES_PROVIDER) ] && echo 'INSTALL_POSTGRES_PROVIDER=$(INSTALL_POSTGRES_PROVIDER)') \ $$([ $(INSTALL_MONGODB_PROVIDER) ] && echo 'INSTALL_MONGODB_PROVIDER=$(INSTALL_MONGODB_PROVIDER)') +ifneq ($(SKIP_DETAILS),true) + $(MAKE) k3d/get-lagoon-details +endif # k3d/stable-install-lagoon is the same as k3d/install-lagoon except that it starts it with the latest stable chart versions .PHONY: k3d/stable-install-lagoon @@ -789,7 +819,10 @@ k3d/stable-install-lagoon: # k3d/local-stack will deploy and seed a lagoon-core with a lagoon-remote and all basic services to get you going # and will provide some initial seed data for a user to jump right in and start using lagoon .PHONY: k3d/local-stack -k3d/local-stack: k3d/setup k3d/install-lagoon k3d/seed-data k3d/get-lagoon-details +k3d/local-stack: k3d/setup + $(MAKE) k3d/install-lagoon SKIP_DETAILS=true + $(MAKE) k3d/seed-data + $(MAKE) k3d/get-lagoon-details # k3d/stable-local-stack is the same as k3d/local-stack except that it starts it with the latest stable chart versions # a helper without having to remember to specify the stable option to the target @@ -854,8 +887,8 @@ k3d/push-images: k3d/get-lagoon-details: @export KUBECONFIG="$$(realpath ./kubeconfig.k3d.$(CI_BUILD_TAG))" && \ echo "===============================" && \ - echo "Lagoon UI URL: https://lagoon-ui.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io" \ - && echo "Lagoon API URL: https://lagoon-api.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io/graphql" \ + echo "Lagoon UI URL: $$([ $(LAGOON_CORE_USE_HTTPS) = true ] && echo "https" || echo "http")://lagoon-ui.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io" \ + && echo "Lagoon API URL: $$([ $(LAGOON_CORE_USE_HTTPS) = true ] && echo "https" || echo "http")://lagoon-api.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io/graphql" \ && echo "Lagoon API admin legacy token: $$(docker run \ -e JWTSECRET="$$($(KUBECTL) get secret -n lagoon-core lagoon-core-secrets -o jsonpath="{.data.JWTSECRET}" | base64 --decode)" \ -e JWTAUDIENCE=api.dev \ @@ -866,12 +899,25 @@ k3d/get-lagoon-details: && echo "SSH Core Service: lagoon-ssh.$$($(KUBECTL) -n lagoon-core get services lagoon-core-ssh -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io:$$($(KUBECTL) -n lagoon-core get services lagoon-core-ssh -o jsonpath='{.spec.ports[0].port}')" \ && echo "SSH Portal Service: lagoon-ssh-portal.$$($(KUBECTL) -n lagoon get services lagoon-remote-ssh-portal -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io:$$($(KUBECTL) -n lagoon get services lagoon-remote-ssh-portal -o jsonpath='{.spec.ports[0].port}')" \ && echo "SSH Token Service: lagoon-token.$$($(KUBECTL) -n lagoon-core get services lagoon-core-ssh-token -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io:$$($(KUBECTL) -n lagoon-core get services lagoon-core-ssh-token -o jsonpath='{.spec.ports[0].port}')" \ - && echo "Keycloak admin URL: https://lagoon-keycloak.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io/auth" \ + && echo "Keycloak admin URL: $$([ $(LAGOON_CORE_USE_HTTPS) = true ] && echo "https" || echo "http")://lagoon-keycloak.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io/auth" \ && echo "Keycloak admin password: $$($(KUBECTL) get secret -n lagoon-core lagoon-core-keycloak -o jsonpath="{.data.KEYCLOAK_ADMIN_PASSWORD}" | base64 --decode)" \ && echo "MailPit (email catching service): http://mailpit.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io" \ && echo "" \ - && echo "You can run 'make k3d/get-lagoon-cli-details' to retreive the configuration command for the lagoon-cli" \ - && echo "" \ + && echo "You can run 'make k3d/get-lagoon-cli-details' to retreive the configuration command for the lagoon-cli" +ifeq ($(LAGOON_CORE_USE_HTTPS),true) + @echo "" \ + && echo "===============================" \ + && echo "IMPORTANT" \ + && echo "Access to the UI is only valid over HTTPS." \ + && echo "You will need to accept the invalid certificates for the following services by visiting the URLS for each in your browser" \ + && echo "otherwise the UI will report strange errors." \ + && echo "* Lagoon UI" \ + && echo "* Lagoon API" \ + && echo "* Lagoon Keycloak" \ + && echo "alternatively import the generated certificate './local-dev/certificates/lagoontest.crt' into trusted authorities for websites in your browser" \ + && echo "===============================" +endif + @echo "" # Use k3d/get-lagoon-details to retrieve information related to accessing the local k3d deployed lagoon and its services .PHONY: k3d/get-lagoon-cli-details @@ -895,9 +941,6 @@ k3d/get-lagoon-cli-details: # it is also called as part of k3d/local-stack though so should not need to be called directly. .PHONY: k3d/seed-data k3d/seed-data: -ifeq (,$(subst ",,$(STABLE_CORE_CHART_APP_VERSION))) - $(eval STABLE_CORE_CHART_APP_VERSION = $(shell $(HELM) search repo lagoon/lagoon-core -o json | $(JQ) -r '.[]|.app_version')) -endif @export KUBECONFIG="$$(realpath ./kubeconfig.k3d.$(CI_BUILD_TAG))" && \ export LAGOON_LEGACY_ADMIN=$$(docker run \ -e JWTSECRET="$$($(KUBECTL) get secret -n lagoon-core lagoon-core-secrets -o jsonpath="{.data.JWTSECRET}" | base64 --decode)" \ @@ -915,7 +958,7 @@ endif envsubst < ./local-dev/k3d-seed-data/00-populate-kubernetes.gql | sed 's/"/\\"/g' | sed 's/\\n/\\\\n/g' | awk -F'\n' '{if(NR == 1) {printf $$0} else {printf "\\n"$$0}}'; \ fi) && \ export SEED_DATA_JSON="{\"query\": \"$$SEED_DATA\"}" && \ - wget --quiet --header "Content-Type: application/json" --header "Authorization: bearer $${LAGOON_LEGACY_ADMIN}" "http://lagoon-api.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io/graphql" --post-data "$$SEED_DATA_JSON" --content-on-error -O - && \ + curl -ks -XPOST -H 'Content-Type: application/json' -H "Authorization: bearer $${LAGOON_LEGACY_ADMIN}" "$$([ $(LAGOON_CORE_USE_HTTPS) = true ] && echo "https" || echo "http")://lagoon-api.$$($(KUBECTL) -n ingress-nginx get services ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}').nip.io/graphql" -d "$$SEED_DATA_JSON" && \ echo "Loading API seed users" && \ if [ $(INSTALL_STABLE_CORE) = true ]; then \ cat <(curl -s https://raw.githubusercontent.com/uselagoon/lagoon/refs/tags/$(STABLE_CORE_CHART_APP_VERSION)/local-dev/k3d-seed-data/seed-users.sh) \ @@ -983,6 +1026,17 @@ k3d/retest: "quay.io/helmpack/chart-testing:$(CHART_TESTING_VERSION)" \ ct install --helm-extra-args "--timeout 60m" +# k3d/generate-ca will generate a CA certificate that will be used to issue certificates within the local-stack +# this CA certificate can be loaded into a web browser so that certificates don't present warnings +.PHONY: k3d/generate-ca +k3d/generate-ca: + @ mkdir -p local-dev/certificates && \ + openssl x509 -enddate -noout -in local-dev/certificates/lagoontest.crt > /dev/null 2>&1 || \ + (openssl genrsa -out local-dev/certificates/lagoontest.key 2048 && \ + openssl req -x509 -new -nodes -key local-dev/certificates/lagoontest.key \ + -sha256 -days 3560 -out local-dev/certificates/lagoontest.crt -addext keyUsage=critical,digitalSignature,keyEncipherment,keyCertSign \ + -subj '/CN=lagoon.test') + .PHONY: k3d/clean k3d/clean: local-dev/k3d $(K3D) cluster delete $(CI_BUILD_TAG) From fbba96ce865767488b7c0df71a8e4e5b47cea659 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Thu, 23 Jan 2025 17:03:31 +1100 Subject: [PATCH 3/4] chore: use ghcr ssh-portal images --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index c3864ffa16..edfe5b94a8 100644 --- a/Makefile +++ b/Makefile @@ -59,13 +59,13 @@ UI_IMAGE_TAG = pr-307 # SSHPORTALAPI_IMAGE_REPO and SSHPORTALAPI_IMAGE_TAG are an easy way to override the ssh portal api image used in the local stack lagoon-core # only works for installations where INSTALL_STABLE_CORE=false -SSHPORTALAPI_IMAGE_REPO = shreddedbacon/ssh-portal-api -SSHPORTALAPI_IMAGE_TAG = latest +SSHPORTALAPI_IMAGE_REPO = ghcr.io/uselagoon/lagoon-ssh-portal/ssh-portal-api +SSHPORTALAPI_IMAGE_TAG = pr-497 # SSHTOKEN_IMAGE_REPO and SSHTOKEN_IMAGE_TAG are an easy way to override the ssh token image used in the local stack lagoon-core # only works for installations where INSTALL_STABLE_CORE=false -SSHTOKEN_IMAGE_REPO = shreddedbacon/ssh-token -SSHTOKEN_IMAGE_TAG = latest +SSHTOKEN_IMAGE_REPO = ghcr.io/uselagoon/lagoon-ssh-portal/ssh-token +SSHTOKEN_IMAGE_TAG = pr-497 # SSHPORTAL_IMAGE_REPO and SSHPORTAL_IMAGE_TAG are an easy way to override the ssh portal image used in the local stack lagoon-remote # only works for installations where INSTALL_STABLE_REMOTE=false From 31ccbb251b7cd0e43bca42f7697a06a9ab1d31a6 Mon Sep 17 00:00:00 2001 From: shreddedbacon Date: Fri, 24 Jan 2025 11:16:32 +1100 Subject: [PATCH 4/4] chore: remove variables and change to relevant flags to startup command --- .../entrypoints/default-keycloak-entrypoint.sh | 16 ---------------- services/keycloak/entrypoints/kc-startup.sh | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/services/keycloak/entrypoints/default-keycloak-entrypoint.sh b/services/keycloak/entrypoints/default-keycloak-entrypoint.sh index ef516d12f5..d885b1b1e1 100755 --- a/services/keycloak/entrypoints/default-keycloak-entrypoint.sh +++ b/services/keycloak/entrypoints/default-keycloak-entrypoint.sh @@ -4,20 +4,4 @@ export KC_DB_USERNAME=$DB_USER export KC_DB_PASSWORD=$DB_PASSWORD export KC_DB_URL=jdbc:$DB_VENDOR://$DB_ADDR:3306/$DB_DATABASE -export KC_PROXY=${KC_PROXY:-edge} -export KC_HOSTNAME_STRICT=${KC_HOSTNAME_STRICT:-false} -export KC_HOSTNAME_STRICT_HTTPS=${KC_HOSTNAME_STRICT_HTTPS:-false} -export KC_HTTP_RELATIVE_PATH=${KC_HTTP_RELATIVE_PATH:-/auth} -export KC_HOSTNAME_URL=${KEYCLOAK_FRONTEND_URL} - -export KC_HOSTNAME_ADMIN_URL=${KEYCLOAK_FRONTEND_URL} - -export KC_DB_POOL_MAX_SIZE=${KEYCLOAK_DS_MAX_POOL_SIZE:-20} -export KC_DB_POOL_MIN_SIZE=${KEYCLOAK_DS_MIN_POOL_SIZE:-0} - -# https://www.keycloak.org/docs/latest/upgrading/#admin-bootstrapping-and-recovery -# https://www.keycloak.org/server/bootstrap-admin-recovery -export KC_BOOTSTRAP_ADMIN_USERNAME=$KEYCLOAK_ADMIN_USER -export KC_BOOTSTRAP_ADMIN_PASSWORD=$KEYCLOAK_ADMIN_PASSWORD - KEYCLOAK_USER=$KEYCLOAK_ADMIN_USER KEYCLOAK_PASSWORD=$KEYCLOAK_ADMIN_PASSWORD KEYCLOAK_ADMIN=$KEYCLOAK_ADMIN_USER /lagoon/kc-startup.sh "$@" diff --git a/services/keycloak/entrypoints/kc-startup.sh b/services/keycloak/entrypoints/kc-startup.sh index abb603dc54..9d08495019 100755 --- a/services/keycloak/entrypoints/kc-startup.sh +++ b/services/keycloak/entrypoints/kc-startup.sh @@ -11,5 +11,18 @@ shopt -s failglob # "--hostname-backchannel-dynamic" # Enables dynamic resolving of backchannel URLs, including hostname, scheme, port and context path. # Set to true if your application accesses Keycloak via a private network. If set to true, hostname option needs to be specified as a full URL. + +# https://www.keycloak.org/server/hostname#_using_edge_tls_termination replaces `KC_PROXY=edge` +# --proxy-headers xforwarded +# --http-enabled + +# it is also possible to expose the admin console on a different hostname using the `--hostname-admin` flag, which could support in the future with a different +# variable than `KEYCLOAK_FRONTEND_URL` perhaps `KEYCLOAK_ADMIN_URL` /opt/keycloak/bin/kc.sh "$@" --features="scripts,token-exchange,admin-fine-grained-authz" \ - --hostname-backchannel-dynamic true --hostname ${KC_HOSTNAME_URL} \ No newline at end of file + --proxy-headers xforwarded \ + --http-enabled true \ + --http-relative-path ${KC_HTTP_RELATIVE_PATH:-/auth} \ + --hostname-backchannel-dynamic true \ + --hostname-strict ${KC_HOSTNAME_STRICT:-false} \ + --hostname ${KEYCLOAK_FRONTEND_URL} \ + --hostname-admin ${KEYCLOAK_FRONTEND_URL}