Skip to content

build-images

build-images #3352

Workflow file for this run

---
# desc: build container images, perform static tests then publish
name: build-images
on:
push:
branches:
- '**'
tags:
- keycloak-[0-9]+-[0-9]+-[0-9]+-[0-9]+-[0-9]+ # `keycloak-23-yyyy-mm-dd-xxx`: only keycloak 23
- '[0-9]+-[0-9]+-[0-9]+-[0-9]+' # `yyyy-mm-dd-xxx`: all keycloak versions
schedule:
- cron: 0 3 * * *
workflow_dispatch:
inputs:
notify_back_error_message:
description: \ Error message if retry was not successful. This parameter is used for internal call back actions.
required: false
default: ''
env:
# Public registry available on docker hub
CONTAINER_REGISTRY_HUB: docker.io
CONTAINER_IMAGE_NAME_HUB: camunda/keycloak
# Enterprise registry available for customers
CONTAINER_REGISTRY_CAMUNDA: registry.camunda.cloud
CONTAINER_IMAGE_NAME_CAMUNDA: keycloak-ee/keycloak
# Internal registry only used for ci tests
CONTAINER_REGISTRY_CI: registry.camunda.cloud
CONTAINER_IMAGE_NAME_CI: team-infrastructure-experience/keycloak
jobs:
triage:
runs-on: ubuntu-24.04
steps:
- name: Display notify_back_error_message if present
if: ${{ inputs.notify_back_error_message != '' }}
run: |
echo "A previous workflow failed but has attempted to retry: ${{ inputs.notify_back_error_message }}"
exit 1
list-keycloak-versions:
runs-on: ubuntu-24.04
needs:
- triage
outputs:
matrix_keycloak_versions: ${{ steps.set-matrix.outputs.matrix_keycloak_versions }}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: List Keycloak Versions from repository's folders
id: set-matrix
run: |
set -euo pipefail
: # if we release a specified version of keycloak, the matrix should only contain it
if [[ $GITHUB_REF =~ ^refs/tags/keycloak-([0-9]+)- ]]; then
keycloak_version=${BASH_REMATCH[1]}
matrix_json=$(jq -n --arg v "$keycloak_version" '["\($v)-prem", "\($v)-hub", "\($v)-quay", "\($v)-quay-optimized"]')
else
: # List folders matching the pattern keycloak-*
: # Export the list as an output in JSON format
versions=$(printf "%s\n" keycloak-*/ | sed 's/\/$//' | sed 's/keycloak-//')
matrix_json=$(echo "$versions" | jq -R -s -c 'split("\n")[:-1] | map("\(.)-prem", "\(.)-hub", "\(.)-quay", "\(.)-quay-optimized") | flatten')
fi
echo "matrix_keycloak_versions=${matrix_json}" | tee -a "$GITHUB_OUTPUT"
build-image:
runs-on: ubuntu-24.04
outputs:
full_image_name: ${{ steps.compute-image-name-step.outputs.full_image_name }}
needs:
- list-keycloak-versions
strategy:
fail-fast: false # don't propagate failing jobs
matrix:
keycloak_version: ${{ fromJson(needs.list-keycloak-versions.outputs.matrix_keycloak_versions) }}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Install asdf tools with cache
uses: camunda/infraex-common-config/./.github/actions/asdf-install-tooling@18718a9ca7599dc71ef3624230ad624720e85ee9 # 1.6.0
- name: Import secrets
uses: hashicorp/vault-action@4c06c5ccf5c0761b6029f56cfb1dcf5565918a3b # v3.4.0
id: secrets
with:
url: ${{ secrets.VAULT_ADDR }}
method: approle
roleId: ${{ secrets.VAULT_ROLE_ID }}
secretId: ${{ secrets.VAULT_SECRET_ID }}
exportEnv: false
secrets: |
secret/data/products/infrastructure-experience/ci/common MACHINE_PWD;
secret/data/products/infrastructure-experience/ci/common MACHINE_USR;
secret/data/products/infrastructure-experience/ci/common DOCKERHUB_USER;
secret/data/products/infrastructure-experience/ci/common DOCKERHUB_PASSWORD;
- name: Login to the dockerhub registry # prevents pull limit rate
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ${{ env.CONTAINER_REGISTRY_HUB }}
username: ${{ steps.secrets.outputs.DOCKERHUB_USER }}
password: ${{ steps.secrets.outputs.DOCKERHUB_PASSWORD }}
- name: Extract version variables
id: version-vars
uses: ./.github/actions/extract-version-vars
with:
keycloak_version: ${{ matrix.keycloak_version }}
- name: Compute build image variables
id: compute-build-image-name-step
run: |
set -euo pipefail
base_path="keycloak-${{ steps.version-vars.outputs.base_version }}" # e.g. "keycloak-24"
base_image_name=$(yq e ".sources.${{ steps.version-vars.outputs.base_type }}.image.repository" "${base_path}/bases.yml")
base_image_tag=$(yq e ".sources.${{ steps.version-vars.outputs.base_type }}.image.tag" "${base_path}/bases.yml" | cut -d@ -f1)
base_image_digest=$(yq e ".sources.${{ steps.version-vars.outputs.base_type }}.image.tag" "${base_path}/bases.yml" | cut -d@ -f2)
# Set the Dockerfile path based on base type
if [[ "${{ steps.version-vars.outputs.base_type }}" == "quay" ]]; then
dockerfile_path="Dockerfile.quay"
else
dockerfile_path="Dockerfile"
fi
echo "base_version=${{ steps.version-vars.outputs.base_version }}" | tee -a "$GITHUB_OUTPUT"
echo "base_type=${{ steps.version-vars.outputs.base_type }}" | tee -a "$GITHUB_OUTPUT"
echo "base_image_name=$base_image_name" | tee -a "$GITHUB_OUTPUT"
echo "base_image_tag=$base_image_tag" | tee -a "$GITHUB_OUTPUT"
echo "base_image_digest=$base_image_digest" | tee -a "$GITHUB_OUTPUT"
echo "dockerfile_path=$dockerfile_path" | tee -a "$GITHUB_OUTPUT"
- name: Build image using Camunda docker build
id: build-image-step
uses: camunda/infra-global-github-actions/build-docker-image@8e32450404891a0eea66404c8cf3cbfe8e602d38 # main
with:
registry_host: ${{ env.CONTAINER_REGISTRY_CI }}
registry_username: ${{ steps.secrets.outputs.MACHINE_USR }}
registry_password: ${{ steps.secrets.outputs.MACHINE_PWD }}
force_push: true
image_name: ${{ env.CONTAINER_IMAGE_NAME_CI }}
build_context: ./keycloak-${{ steps.compute-build-image-name-step.outputs.base_version }}/
build_docker_file: |
./keycloak-${{ steps.compute-build-image-name-step.outputs.base_version }}/${{ steps.compute-build-image-name-step.outputs.dockerfile_path }}
build_platforms: linux/amd64,linux/arm64
build_args: |
BASE_IMAGE_NAME=${{ steps.compute-build-image-name-step.outputs.base_image_name }}
BASE_IMAGE_TAG=${{ steps.compute-build-image-name-step.outputs.base_image_tag }}
BASE_IMAGE_DIGEST=${{ steps.compute-build-image-name-step.outputs.base_image_digest }}
BUILD_OPTIMIZED=${{ steps.version-vars.outputs.is_optimized }}
extra_tags: |
type=sha,enable=true,priority=1000,prefix=ci-${{ matrix.keycloak_version }}-sha-,suffix=,format=short
- name: Compute target built image fully qualified name from metadata
id: compute-image-name-step
env:
IMAGE_METADATA: ${{ steps.build-image-step.outputs.image_metadata }}
run: |
set -euo pipefail
image_name=$(echo "${IMAGE_METADATA}" | tr -d '\n' | jq -r '."image.name"' | tr ',' '\n' | head -n 1 | tr -d ' ')
digest=$(echo "${IMAGE_METADATA}" | tr -d '\n' | jq -r '."containerimage.digest"')
full_image_name="${image_name}@${digest}"
echo "full_image_name=${full_image_name}" | tee -a "$GITHUB_OUTPUT"
## Write for matrix outputs workaround
- uses: cloudposse/github-action-matrix-outputs-write@ed06cf3a6bf23b8dce36d1cf0d63123885bb8375 # v1
id: out
with:
matrix-step-name: ${{ github.job }}
matrix-key: ${{ matrix.keycloak_version }}
outputs: |-
full_image_name: ${{ steps.compute-image-name-step.outputs.full_image_name }}
## Read matrix outputs
read-build-image-output:
runs-on: ubuntu-24.04
needs: [build-image]
steps:
- uses: cloudposse/github-action-matrix-outputs-read@33cac12fa9282a7230a418d859b93fdbc4f27b5a # v1
id: read
with:
matrix-step-name: build-image
outputs:
result: ${{ steps.read.outputs.result }}
test-base-image:
runs-on: ubuntu-24.04
needs:
- list-keycloak-versions
- build-image
- read-build-image-output
strategy:
fail-fast: false # don't propagate failing jobs
matrix:
keycloak_version: ${{ fromJson(needs.list-keycloak-versions.outputs.matrix_keycloak_versions) }}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Install asdf tools with cache
uses: camunda/infraex-common-config/./.github/actions/asdf-install-tooling@18718a9ca7599dc71ef3624230ad624720e85ee9 # 1.6.0
- name: Set Keycloak Image Name
id: set-keycloak-image-name
shell: bash
run: |
set -euo pipefail
keycloak_image_name="${{ fromJson(needs.read-build-image-output.outputs.result).full_image_name[matrix.keycloak_version] }}"
echo "keycloak_image_name=${keycloak_image_name}" | tee -a "$GITHUB_ENV"
- name: Import secrets
uses: hashicorp/vault-action@4c06c5ccf5c0761b6029f56cfb1dcf5565918a3b # v3.4.0
id: secrets
with:
url: ${{ secrets.VAULT_ADDR }}
method: approle
roleId: ${{ secrets.VAULT_ROLE_ID }}
secretId: ${{ secrets.VAULT_SECRET_ID }}
exportEnv: false
secrets: |
secret/data/products/infrastructure-experience/ci/common MACHINE_PWD;
secret/data/products/infrastructure-experience/ci/common MACHINE_USR;
- name: Login to the registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ${{ env.CONTAINER_REGISTRY_CI }}
username: ${{ steps.secrets.outputs.MACHINE_USR }}
password: ${{ steps.secrets.outputs.MACHINE_PWD }}
- name: Extract version variables
id: version-vars
uses: ./.github/actions/extract-version-vars
with:
keycloak_version: ${{ matrix.keycloak_version }}
include_optimized: 'false'
include_image_type: 'true'
- name: Check Keycloak Providers/Config
run: |
set -euo pipefail
python3 ./.github/scripts/build-check/check_providers.py "${{ env.keycloak_image_name }}" "${{ steps.version-vars.outputs.image_type }}"
test-postgres-integ:
strategy:
fail-fast: false # don't propagate failing jobs
matrix:
runner_desc:
- runner: ubuntu-24.04
postgres_replicas: 1
keycloak_jdbc_driver: postgresql
keycloak_db_driver: org.postgresql.Driver
keycloak_db_host_template: postgres
keycloak_db_jdbc_query: ''
keycloak_db_port: '5432'
- runner: aws-core-2-default
postgres_replicas: 0
keycloak_jdbc_driver: aws-wrapper:postgresql
keycloak_db_driver: software.amazon.jdbc.Driver
keycloak_db_host_template: camunda-ci-eks-aurora-postgresql-{{ postgres_version }}.cluster-clnwzia8ptad.eu-central-1.rds.amazonaws.com
keycloak_db_jdbc_query: wrapperPlugins=iam&ssl=true&sslmode=require
keycloak_db_port: '5432'
- runner: aws-arm-core-2-default
postgres_replicas: 0
keycloak_jdbc_driver: aws-wrapper:postgresql
keycloak_db_driver: software.amazon.jdbc.Driver
keycloak_db_host_template: camunda-ci-eks-aurora-postgresql-{{ postgres_version }}.cluster-clnwzia8ptad.eu-central-1.rds.amazonaws.com
keycloak_db_jdbc_query: wrapperPlugins=iam&ssl=true&sslmode=require
keycloak_db_port: '5432'
# Add the gcp runner when GCloud SQL is available
# GCloud SQL is not tested yet as we don't have a dedicated db
keycloak_version: ${{ fromJson(needs.list-keycloak-versions.outputs.matrix_keycloak_versions) }}
runs-on: ${{ matrix.runner_desc.runner }}
needs:
- list-keycloak-versions
- build-image
- read-build-image-output
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Install build-essentials for asdf
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y build-essential git libexpat1-dev libssl-dev zlib1g-dev \
libncurses5-dev libbz2-dev liblzma-dev \
libsqlite3-dev libffi-dev tcl-dev linux-headers-generic libgdbm-dev \
libreadline-dev tk tk-dev
- name: Install asdf tools with cache
uses: camunda/infraex-common-config/./.github/actions/asdf-install-tooling@18718a9ca7599dc71ef3624230ad624720e85ee9 # 1.6.0
- name: Set Keycloak Image Name
id: set-keycloak-image-name
shell: bash
run: |
set -euo pipefail
keycloak_image_name="${{ fromJson(needs.read-build-image-output.outputs.result).full_image_name[matrix.keycloak_version] }}"
echo "keycloak_image_name=${keycloak_image_name}" | tee -a "$GITHUB_ENV"
- name: Import secrets
uses: hashicorp/vault-action@4c06c5ccf5c0761b6029f56cfb1dcf5565918a3b # v3.4.0
id: secrets
with:
url: ${{ secrets.VAULT_ADDR }}
method: approle
roleId: ${{ secrets.VAULT_ROLE_ID }}
secretId: ${{ secrets.VAULT_SECRET_ID }}
exportEnv: true
secrets: |
secret/data/products/infrastructure-experience/ci/common MACHINE_PWD;
secret/data/products/infrastructure-experience/ci/common MACHINE_USR;
secret/data/products/infrastructure-experience/aurorapg AURORA_POSTGRESQL_PASSWORD | postgres_superuser_password;
secret/data/products/infrastructure-experience/aurorapg AURORA_POSTGRESQL_USERNAME | postgres_superuser;
secret/data/products/infrastructure-experience/ci/common DOCKERHUB_USER;
secret/data/products/infrastructure-experience/ci/common DOCKERHUB_PASSWORD;
- name: Login to the dockerhub registry # prevents pull limit rate
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ${{ env.CONTAINER_REGISTRY_HUB }}
username: ${{ steps.secrets.outputs.DOCKERHUB_USER }}
password: ${{ steps.secrets.outputs.DOCKERHUB_PASSWORD }}
- name: Login to the registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ${{ env.CONTAINER_REGISTRY_CI }}
username: ${{ steps.secrets.outputs.MACHINE_USR }}
password: ${{ steps.secrets.outputs.MACHINE_PWD }}
- name: Extract version variables
id: version-vars
uses: ./.github/actions/extract-version-vars
with:
keycloak_version: ${{ matrix.keycloak_version }}
include_optimized: 'false'
- name: Compute AWS variables
if: startsWith(matrix.runner_desc.runner, 'aws')
run: |
set -euo pipefail
: # aws aurora superuser is only used for bootstrapping a standard user that will auth using irsa
echo "postgres_user=keycloak-irsa" | tee -a "$GITHUB_ENV"
echo "postgres_password=" | tee -a "$GITHUB_ENV"
echo "compose_keycloak_volume_1=$AWS_WEB_IDENTITY_TOKEN_FILE:$AWS_WEB_IDENTITY_TOKEN_FILE" >> "$GITHUB_ENV"
: # export AWS variables
echo "AWS_STS_REGIONAL_ENDPOINTS=$AWS_STS_REGIONAL_ENDPOINTS" | tee -a "$GITHUB_ENV"
echo "AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION" | tee -a "$GITHUB_ENV"
echo "AWS_REGION=$AWS_REGION" | tee -a "$GITHUB_ENV"
echo "AWS_ROLE_ARN=$AWS_ROLE_ARN" | tee -a "$GITHUB_ENV"
echo "AWS_WEB_IDENTITY_TOKEN_FILE=$AWS_WEB_IDENTITY_TOKEN_FILE" | tee -a "$GITHUB_ENV"
- name: Compute Ubuntu variables
if: startsWith(matrix.runner_desc.runner, 'ubuntu')
run: |
set -euo pipefail
: # we use plain values that will be used by the postgres container
echo "postgres_user=keycloak" | tee -a "$GITHUB_ENV"
echo "postgres_password=password" | tee -a "$GITHUB_ENV"
- name: Declare test recipe variables
shell: bash
run: |
set -euo pipefail
if (( "${{ matrix.runner_desc.postgres_replicas }}" < 1 )); then
echo "compose_keycloak_depends_on=" | tee -a "$GITHUB_ENV"
else
echo "compose_keycloak_depends_on=postgres" | tee -a "$GITHUB_ENV"
fi
: # ensure uniqueness of the db name
uuid="$(cat /proc/sys/kernel/random/uuid)"
postgres_database="infex-keycloak-db-${uuid}-${{ github.sha }}"
echo "postgres_database=${postgres_database}" | tee -a "$GITHUB_ENV"
: # get the postgres version to test
keycloak_version_git="$(echo '${{ matrix.keycloak_version }}' | sed -E 's/^([0-9]+)\.?(.*)$/\1.0/g')" # make sure to have a major.0 format
postgres_version=$(
curl -s "https://raw.githubusercontent.com/keycloak/keycloak/release/${keycloak_version_git}/pom.xml" \
| awk -F'[><]' '/<postgresql.version>/{print $3}'
)
echo "postgres_version=${postgres_version}" | tee -a "$GITHUB_ENV"
: # apply template on the address
postgres_host=$(echo "${{ matrix.runner_desc.keycloak_db_host_template }}" | sed "s/{{ postgres_version }}/${postgres_version}/g")
echo "postgres_host=${postgres_host}" | tee -a "$GITHUB_ENV"
# The self-hosted runner doesn't provide a postgres client and the prerequisites for make,
# so we need to install them manually
- name: Install required packages
run: sudo apt-get update && sudo apt-get install -y build-essential postgresql-client
- name: Tear up Aurora PG (aws only)
if: startsWith(matrix.runner_desc.runner, 'aws')
run: ./.helpers/actions/create_aurora_pg_db.sh
env:
PGDATABASE: ${{ env.postgres_database }}
PGHOST: ${{ env.postgres_host }}
PGPORT: ${{ matrix.runner_desc.keycloak_db_port }}
PGPASSWORD: ${{ env.postgres_superuser_password }}
PGUSER: ${{ env.postgres_superuser }}
PGUSER_IRSA: ${{ env.postgres_user }}
- name: Generate a db auth token using aws for simple psql db connection test (aws only)
if: startsWith(matrix.runner_desc.runner, 'aws')
shell: bash
run: |
set -euo pipefail
: # We generate a db auth token using the aws cli because IRSA access in Keycloak might not be easy to debug.
: # This token will be used in the "Test psql db connection" step, and then it will be reset for the Keycloak integration test.
: # The aws command uses the environment variables provided by the runner
AWS_PG_PASSWORD="$(aws rds generate-db-auth-token --hostname ${{ env.postgres_host }} \
--port ${{ matrix.runner_desc.keycloak_db_port }} --region ${{ env.AWS_REGION }} --username ${{ env.postgres_user }})"
echo "postgres_password=${AWS_PG_PASSWORD}" >> "$GITHUB_ENV"
- name: Test psql db connection (for external db only)
if: ${{ matrix.runner_desc.postgres_replicas == 0 }}
shell: bash
run: |
set -euo pipefail
: # Perform a simple psql connection test to ensure the database can be reached.
: # The psql command provides clear and simple error messages compared to jdbc,
: # which is why we perform this step.
PGPASSWORD="${{ env.postgres_password }}"
export PGPASSWORD
psql -h "${{ env.postgres_host }}" -p "${{ matrix.runner_desc.keycloak_db_port }}" \
"dbname=${{ env.postgres_database }} user=${{ env.postgres_user }}" -c 'SELECT version();'
- name: Reset postgres_password for IRSA connection (aws only)
if: startsWith(matrix.runner_desc.runner, 'aws')
shell: bash
run: |
set -euo pipefail
: # For AWS IRSA connection, we don't use password-based authentication.
: # Since a password was generated in the previous steps, we need to ensure it is empty.
echo "postgres_password=" >> "$GITHUB_ENV"
- name: Set compose file based on image type
id: set-compose-file
run: |
set -euo pipefail
if [[ "${{ steps.version-vars.outputs.base_type }}" == "quay" ]]; then
echo "compose_file=docker-compose.quay.yml" | tee -a "$GITHUB_OUTPUT"
else
echo "compose_file=docker-compose.yml" | tee -a "$GITHUB_OUTPUT"
fi
- name: Start Test Environment
uses: ./.github/actions/compose
with:
project_name: keycloak
compose_file: ${{ steps.set-compose-file.outputs.compose_file }}
env:
POSTGRES_DB: ${{ env.postgres_database }}
POSTGRES_USER: ${{ env.postgres_user }}
POSTGRES_PASSWORD: ${{ env.postgres_password }}
KEYCLOAK_DATABASE_USER: ${{ env.postgres_user }}
KEYCLOAK_DATABASE_PASSWORD: ${{ env.postgres_password }}
KEYCLOAK_DATABASE_NAME: ${{ env.postgres_database }}
KEYCLOAK_DATABASE_HOST: ${{ env.postgres_host }}
KEYCLOAK_DATABASE_PORT: ${{ matrix.runner_desc.keycloak_db_port }}
KEYCLOAK_JDBC_DRIVER: ${{ matrix.runner_desc.keycloak_jdbc_driver }}
KEYCLOAK_JDBC_PARAMS: ${{ matrix.runner_desc.keycloak_db_jdbc_query }}
KC_DB: postgres
KC_DB_DRIVER: ${{ matrix.runner_desc.keycloak_db_driver }}
KC_TRANSACTION_XA_ENABLED: false
KC_HEALTH_ENABLED: true
KC_METRICS_ENABLED: true
# Disable HTTPS for tests - force HTTP mode
KC_HTTP_ENABLED: true
KC_HOSTNAME_STRICT_HTTPS: false
KC_HOSTNAME_STRICT: false
# Bootstrap admin user for Quay images
KC_BOOTSTRAP_ADMIN_USERNAME: admin
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
# Alternative admin user variables (for compatibility, KC_BOOTSTRAP is not sufficient)
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
KEYCLOAK_LOG_LEVEL: INFO,software.amazon.jdbc:INFO
COMPOSE_POSTGRES_IMAGE: docker.io/postgres:${{ env.postgres_version }}
COMPOSE_POSTGRES_DEPLOY_REPLICAS: ${{ matrix.runner_desc.postgres_replicas }}
COMPOSE_KEYCLOAK_DEPENDS_ON: ${{ env.compose_keycloak_depends_on }}
COMPOSE_KEYCLOAK_VOLUME_1: ${{ env.compose_keycloak_volume_1 || '/dev/null:/dummynull1' }}
COMPOSE_KEYCLOAK_IMAGE: ${{ env.keycloak_image_name }}
# AWS specific variables to forward,
# see https://confluence.camunda.com/pages/viewpage.action?pageId=178590693#IAMRolesforServiceAccountsTesting(IRSA)-EnvironmentVariables
AWS_STS_REGIONAL_ENDPOINTS: ${{ env.AWS_STS_REGIONAL_ENDPOINTS }}
AWS_DEFAULT_REGION: ${{ env.AWS_DEFAULT_REGION }}
AWS_REGION: ${{ env.AWS_REGION }}
AWS_ROLE_ARN: ${{ env.AWS_ROLE_ARN }}
AWS_WEB_IDENTITY_TOKEN_FILE: ${{ env.AWS_WEB_IDENTITY_TOKEN_FILE }}
- name: Install dependencies
run: |
set -euo pipefail
python -m pip install --upgrade pip
pip install -r ./.github/scripts/integration/requirements.txt
- name: Test Environment
run: python3 ./.github/scripts/integration/main.py
- name: Tear down Aurora PG (aws only)
if: startsWith(matrix.runner_desc.runner, 'aws') && always()
run: ./.helpers/actions/delete_aurora_pg_db.sh
env:
PGDATABASE: ${{ env.postgres_database }}
PGHOST: ${{ env.postgres_host }}
PGPORT: ${{ matrix.runner_desc.keycloak_db_port }}
PGPASSWORD: ${{ env.postgres_superuser_password }}
PGUSER: ${{ env.postgres_superuser }}
publish-image:
runs-on: ubuntu-24.04
# to release all versions of keycloak, tag it using the date (e.g.: `2024-03-10-001`)
# to release only one version keycloak, tag it using the date prefixed by the version of keycloak (e.g.: `keycloak-23-2024-03-10-001`)
if: startsWith(github.ref, 'refs/tags')
strategy:
fail-fast: false # don't propagate failing jobs
matrix:
keycloak_version: ${{ fromJson(needs.list-keycloak-versions.outputs.matrix_keycloak_versions) }}
needs:
- read-build-image-output
- list-keycloak-versions
- test-postgres-integ
- test-base-image
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Install if required common software tooling
uses: camunda/infra-global-github-actions/common-tooling@8e32450404891a0eea66404c8cf3cbfe8e602d38 # main
with:
node-enabled: false
java-enabled: false
yarn-enabled: false
python-enabled: false
buildx-install: true
- name: Install asdf tools with cache
uses: camunda/infraex-common-config/./.github/actions/asdf-install-tooling@18718a9ca7599dc71ef3624230ad624720e85ee9 # 1.6.0
- name: Import secrets
uses: hashicorp/vault-action@4c06c5ccf5c0761b6029f56cfb1dcf5565918a3b # v3.4.0
id: secrets
with:
url: ${{ secrets.VAULT_ADDR }}
method: approle
roleId: ${{ secrets.VAULT_ROLE_ID }}
secretId: ${{ secrets.VAULT_SECRET_ID }}
exportEnv: false
secrets: |
secret/data/products/infrastructure-experience/ci/common MACHINE_PWD;
secret/data/products/infrastructure-experience/ci/common MACHINE_USR;
secret/data/products/infrastructure-experience/ci/common DOCKERHUB_USER;
secret/data/products/infrastructure-experience/ci/common DOCKERHUB_PASSWORD;
- name: Login to the registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ${{ env.CONTAINER_REGISTRY_CI }}
username: ${{ steps.secrets.outputs.MACHINE_USR }}
password: ${{ steps.secrets.outputs.MACHINE_PWD }}
- name: Extract version variables
id: version-vars
uses: ./.github/actions/extract-version-vars
with:
keycloak_version: ${{ matrix.keycloak_version }}
- name: Set registry credentials based on keycloak_version
id: publishing-registry
run: |
version="${{ matrix.keycloak_version }}"
if [[ "${{ steps.version-vars.outputs.base_type }}" == "hub" ]]; then
echo "publishing_registry=${{ env.CONTAINER_REGISTRY_HUB }}" | tee -a "$GITHUB_OUTPUT"
echo "publishing_registry_username=${{ steps.secrets.outputs.DOCKERHUB_USER }}" | tee -a "$GITHUB_OUTPUT"
echo "publishing_registry_password=${{ steps.secrets.outputs.DOCKERHUB_PASSWORD }}" | tee -a "$GITHUB_OUTPUT"
# Image target for Hub
echo "publishing_image_name=${{ env.CONTAINER_IMAGE_NAME_HUB }}" | tee -a "$GITHUB_OUTPUT"
elif [[ "${{ steps.version-vars.outputs.base_type }}" == "prem" ]]; then
echo "publishing_registry=${{ env.CONTAINER_REGISTRY_CAMUNDA }}" | tee -a "$GITHUB_OUTPUT"
echo "publishing_registry_username=${{ steps.secrets.outputs.MACHINE_USR }}" | tee -a "$GITHUB_OUTPUT"
echo "publishing_registry_password=${{ steps.secrets.outputs.MACHINE_PWD }}" | tee -a "$GITHUB_OUTPUT"
# Image target for Camunda
echo "publishing_image_name=${{ env.CONTAINER_IMAGE_NAME_CAMUNDA }}" | tee -a "$GITHUB_OUTPUT"
elif [[ "${{ steps.version-vars.outputs.base_type }}" == "quay" ]]; then
echo "publishing_registry=${{ env.CONTAINER_REGISTRY_HUB }}" | tee -a "$GITHUB_OUTPUT"
echo "publishing_registry_username=${{ steps.secrets.outputs.DOCKERHUB_USER }}" | tee -a "$GITHUB_OUTPUT"
echo "publishing_registry_password=${{ steps.secrets.outputs.DOCKERHUB_PASSWORD }}" | tee -a "$GITHUB_OUTPUT"
# Image target for Hub with quay- prefix in tags
echo "publishing_image_name=${{ env.CONTAINER_IMAGE_NAME_HUB }}" | tee -a "$GITHUB_OUTPUT"
else
echo "❌ Error: Unsupported version suffix in '$version'. Expected '-hub', '-prem', or '-quay'."
exit 1
fi
- name: Login to the publishing registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ${{ steps.publishing-registry.outputs.publishing_registry }}
username: ${{ steps.publishing-registry.outputs.publishing_registry_username }}
password: ${{ steps.publishing-registry.outputs.publishing_registry_password }}
- name: Set Keycloak Version
id: set-keycloak-version
run: |
set -euo pipefail
keycloak_image_name="${{ fromJson(needs.read-build-image-output.outputs.result).full_image_name[matrix.keycloak_version] }}"
echo "keycloak_image_name=${keycloak_image_name}" | tee -a "$GITHUB_OUTPUT"
publishing_image_target_name="${{ steps.publishing-registry.outputs.publishing_registry }}/${{ steps.publishing-registry.outputs.publishing_image_name }}"
echo "publishing_image_target_name=${publishing_image_target_name}" | tee -a "$GITHUB_OUTPUT"
- name: Pull built image
run: |
set -euo pipefail
docker pull "${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
- name: Retag and push the image
shell: bash
run: |
set -euo pipefail
base_path="keycloak-${{ steps.version-vars.outputs.base_version }}" # e.g. "keycloak-24"
# e.g. base_image_tag=23.0.7-debian-12-r5 or 23.0.7 for quay
base_image_tag=$(yq e ".sources.${{ steps.version-vars.outputs.base_type }}.image.tag" "${base_path}/bases.yml" | cut -d@ -f1)
echo "base_image_tag=${base_image_tag}"
: # version of keycloak (e.g.: 23.0.1)
# For quay images, the tag is just the semver, for bitnami it includes extra suffix
if [[ "${{ steps.version-vars.outputs.base_type }}" == "quay" ]]; then
semver_tag=$(echo "${base_image_tag}" | awk -F'-' '{print $1}')
if [[ "${{ steps.version-vars.outputs.is_optimized }}" == "true" ]]; then
tag_prefix="quay-optimized-"
else
tag_prefix="quay-"
fi
elif [[ "${{ steps.version-vars.outputs.base_type }}" == "hub" ]]; then
semver_tag=$(echo "${base_image_tag}" | awk -F'-' '{print $1}')
tag_prefix="bitnami-"
elif [[ "${{ steps.version-vars.outputs.base_type }}" == "prem" ]]; then
semver_tag=$(echo "${base_image_tag}" | awk -F'-' '{print $1}')
tag_prefix="bitnami-ee-"
else
echo "❌ Error: Unsupported base_type '${{ steps.version-vars.outputs.base_type }}'. Expected 'hub', 'prem', or 'quay'."
exit 1
fi
: # remove keycloak- prefix
suffix_version=$(echo '${{ github.ref_name }}' | sed 's/keycloak-[0-9]*-//')
# Create tags with appropriate prefix
docker buildx imagetools create \
-t "${{ steps.set-keycloak-version.outputs.publishing_image_target_name }}:${tag_prefix}${{ steps.version-vars.outputs.base_version }}" \
"${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
docker buildx imagetools create \
-t "${{ steps.set-keycloak-version.outputs.publishing_image_target_name }}:${tag_prefix}${base_image_tag}" \
"${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
docker buildx imagetools create \
-t "${{ steps.set-keycloak-version.outputs.publishing_image_target_name }}:${tag_prefix}${base_image_tag}-${suffix_version}" \
"${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
docker buildx imagetools create -t "${{ steps.set-keycloak-version.outputs.publishing_image_target_name }}:${tag_prefix}${semver_tag}" \
"${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
# For backward compatibility, also publish bitnami images without prefix
base_type="${{ steps.version-vars.outputs.base_type }}"
if [[ "$base_type" == "hub" || "$base_type" == "prem" ]]; then
docker buildx imagetools create \
-t "${{ steps.set-keycloak-version.outputs.publishing_image_target_name }}:${{ steps.version-vars.outputs.base_version }}" \
"${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
docker buildx imagetools create -t "${{ steps.set-keycloak-version.outputs.publishing_image_target_name }}:${base_image_tag}" \
"${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
docker buildx imagetools create -t "${{ steps.set-keycloak-version.outputs.publishing_image_target_name }}:${base_image_tag}-${suffix_version}" \
"${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
docker buildx imagetools create -t "${{ steps.set-keycloak-version.outputs.publishing_image_target_name }}:${semver_tag}" \
"${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
fi
# Make Quay standard (non-optimized) the default latest
if [ "$(./.github/scripts/utils/find_latest_keycloak.sh)" = "${{ steps.version-vars.outputs.base_version }}" ]; then
if [[ "${{ steps.version-vars.outputs.base_type }}" == "quay" && "${{ steps.version-vars.outputs.is_optimized }}" == "false" ]]; then
# Quay standard becomes the main latest
docker buildx imagetools create -t "${{ steps.set-keycloak-version.outputs.publishing_image_target_name }}:latest" \
"${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
fi
# Create prefixed latest tags for all types
docker buildx imagetools create -t "${{ steps.set-keycloak-version.outputs.publishing_image_target_name }}:${tag_prefix}latest" \
"${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
# For backward compatibility, also create non-prefixed latest for bitnami hub images
# (prem images are in a different registry so no conflict with quay)
if [[ "${{ steps.version-vars.outputs.base_type }}" == "hub" ]]; then
docker buildx imagetools create -t "${{ steps.set-keycloak-version.outputs.publishing_image_target_name }}:latest-bitnami" \
"${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
elif [[ "${{ steps.version-vars.outputs.base_type }}" == "prem" ]]; then
# Prem images are in separate registry, so they can have their own latest
docker buildx imagetools create -t "${{ steps.set-keycloak-version.outputs.publishing_image_target_name }}:latest" \
"${{ steps.set-keycloak-version.outputs.keycloak_image_name }}"
fi
fi
# Rerun failed jobs running on self-hosted runners in case of network issues or node preemption
rerun-failed-jobs:
needs:
- test-postgres-integ
if: failure() && fromJSON(github.run_attempt) < 3 && inputs.notify_back_error_message == ''
runs-on: ubuntu-latest
steps:
- name: Retrigger job
uses: camunda/infra-global-github-actions/rerun-failed-run@8e32450404891a0eea66404c8cf3cbfe8e602d38 # main
with:
error-messages: |
lost communication with the server
The runner has received a shutdown signal
run-id: ${{ github.run_id }}
repository: ${{ github.repository }}
vault-addr: ${{ secrets.VAULT_ADDR }}
vault-role-id: ${{ secrets.VAULT_ROLE_ID }}
vault-secret-id: ${{ secrets.VAULT_SECRET_ID }}
notify-back-on-error: 'true'
notify-on-failure:
runs-on: ubuntu-latest
if: failure() && (fromJSON(github.run_attempt) >= 3 || inputs.notify_back_error_message != '') && github.event_name == 'schedule'
needs:
- publish-image
- read-build-image-output
- list-keycloak-versions
- test-postgres-integ
- test-base-image
- rerun-failed-jobs
steps:
- name: Notify in Slack in case of failure
id: slack-notification
uses: camunda/infraex-common-config/.github/actions/report-failure-on-slack@18718a9ca7599dc71ef3624230ad624720e85ee9 # 1.6.0
with:
vault_addr: ${{ secrets.VAULT_ADDR }}
vault_role_id: ${{ secrets.VAULT_ROLE_ID }}
vault_secret_id: ${{ secrets.VAULT_SECRET_ID }}