diff --git a/build-pipeline-yocto.yml.jinja2 b/build-pipeline-yocto.yml.jinja2
index a0dc9b933485efb329c41b5f1b24c49e46e0d9b1..5fdb99cfe8c1225a36d41186d6e8bc398f6063e8 100644
--- a/build-pipeline-yocto.yml.jinja2
+++ b/build-pipeline-yocto.yml.jinja2
@@ -33,6 +33,12 @@ variables:
 changelog:
   extends: .changelog
 
+build-version:
+  extends: .build_version
+  variables:
+    # We have to set a machine, even if it is not actually needed for what the job does,
+    # so we just choose the first.
+    MACHINE: {{ MACHINES.split(' ')[0] }}
 
 # --------------------------------------------------------------------------------------
 # Generated jobs
diff --git a/build-pipeline.yml b/build-pipeline.yml
index 1d2d25049d3926a66a77fe173f1a5bf18b82b8b7..98f20d6c7cbe44dcaf144f1b69a165ac5d524247 100644
--- a/build-pipeline.yml
+++ b/build-pipeline.yml
@@ -96,22 +96,23 @@ workflow:
       fi
     fi
 
-.build_script: &build_script
-  # setup build environment
+.setup_build: &setup_build
   - echo "Build configuration MACHINE=${MACHINE}
       DISTRO=${YOCTO_DISTRO} IMAGE=${YOCTO_IMAGE}"
   - echo "Using build dir ${BUILD_PATH}"
   - export MACHINE="${MACHINE}"
   - export DISTRO="${YOCTO_DISTRO}"
   - export EULA="1"
-  - source ./"${SETUP_SCRIPT}" "${BUILD_PATH}"
-  # start build
+  - source "${SETUP_SCRIPT}" "${BUILD_PATH}"
+
+.run_build: &run_build
   - echo -e "section_start:`date +%s`:bitbake_run\r\e[0KBitbake Log"
   - echo "bitbake ${YOCTO_IMAGE} -c ${BITBAKE_TASK}"
   - bitbake "${YOCTO_IMAGE}" -c "${BITBAKE_TASK}"
   - echo -e "section_end:`date +%s`:bitbake_run\r\e[0K"
 
 .save_build_env: &save_build_env
+  - cd ${CI_PROJECT_DIR}
   # Artifact paths are needed for packaging
   - echo "IMAGE_PATH=${IMAGE_PATH}" > build.env
   - echo "SDK_PATH=${SDK_PATH}" >> build.env
@@ -140,6 +141,40 @@ workflow:
     paths:
       - "changelog.md"
 
+.build_version:
+  extends:
+    - .build_yocto
+  stage: Infrastructure
+  tags:
+    - infrastructure
+  needs: []
+  rules:
+    - when: always
+  variables:
+    BITBAKE_ENV_COMMAND: bitbake ${YOCTO_IMAGE} -e
+    # RELEASE_VERSION and RELEASE_NAME are eval'ed before saving them to version.env,
+    # so we can use deferred variable expansion or even command execution to construct
+    # their values.
+    RELEASE_VERSION: $${DISTRO_VERSION}
+    RELEASE_NAME: Yocto-${RELEASE_VERSION}
+  script:
+    # Extract all variable assignments from the BitBake environment and source them.
+    # The rather complicated regex also regards values containing escaped quotes.
+    - source <( ${BITBAKE_ENV_COMMAND} | egrep '^[A-Z]\w*="([^\\"]+|\\.)*"$' )
+    - echo ${RELEASE_VERSION}
+    - echo ${RELEASE_NAME}
+    - RELEASE_VERSION=$(eval echo "${RELEASE_VERSION}")
+    - RELEASE_NAME=$(eval echo "${RELEASE_NAME}")
+    - echo "RELEASE_VERSION=${RELEASE_VERSION}" >> ${CI_PROJECT_DIR}/version.env
+    - echo "RELEASE_NAME=${RELEASE_NAME}" >> ${CI_PROJECT_DIR}/version.env
+    - cat ${CI_PROJECT_DIR}/version.env
+  artifacts:
+    expire_in: 1 week
+    reports:
+      dotenv: version.env
+    paths: []
+  cache: []
+
 # --------------------------------------------------------------------------------------
 # Stage: build
 # --------------------------------------------------------------------------------------
@@ -220,10 +255,11 @@ workflow:
     - *docker_check
     - *setup_ssh
     - *repo_checkout
+    - *setup_build
   script:
-    - *save_build_env
-    - *build_script
+    - *run_build
     - *collect_srcrevs
+    - *save_build_env
     - *dump_install_command
 
 # --------------------------------------------------------------------------------------
diff --git a/manifest-pipeline-ci-test.yml b/manifest-pipeline-ci-test.yml
index 362c2b4a064dd250a95d030fc99d6e1fec1644c7..e58b2cd2a7af2c2065b8895b84cd03be17067ed6 100644
--- a/manifest-pipeline-ci-test.yml
+++ b/manifest-pipeline-ci-test.yml
@@ -72,7 +72,9 @@ yocto-simulation-pipeline:
       https://git.seco.com/seco-ne/yocto/manifest/-/jobs/artifacts/kirkstone/7.0/download?job=build
     YOCTO_IMAGE: seconorth-image
     YOCTO_DISTRO: seconorth-wayland
+    SETUP_SCRIPT: /dev/null
     INSTALL_SCRIPT: fng-install.sh
+    BITBAKE_ENV_COMMAND: echo DISTRO_VERSION="kirkstone-7.0"
     ARTIFACTS_PATH: build-*/tmp/deploy/images/**/*
     PACKAGE_TYPE: image
     TEST_STAGE: "true"
@@ -92,7 +94,9 @@ sdk-simulation-pipeline:
       https://git.seco.com/seco-ne/yocto/manifest/-/jobs/artifacts/kirkstone/7.0/download?job=buildsdk
     YOCTO_IMAGE: seconorth-image
     YOCTO_DISTRO: seconorth-wayland
+    SETUP_SCRIPT: /dev/null
     INSTALL_SCRIPT: fng-install.sh
+    BITBAKE_ENV_COMMAND: echo DISTRO_VERSION="kirkstone-7.0"
     ARTIFACTS_PATH: build-*/tmp/deploy/sdk/*
     MANUAL_BUILD: "true"
     PACKAGE_TYPE: sdk
diff --git a/manifest-pipeline-yocto.yml b/manifest-pipeline-yocto.yml
index 7dd54297409e12210fe5a3fc1c9a1cee5ebf1427..4844d4cf864a2d57702b39fc33c79d1aef9734bf 100644
--- a/manifest-pipeline-yocto.yml
+++ b/manifest-pipeline-yocto.yml
@@ -96,6 +96,15 @@ fngsystem-pipeline:
     YOCTO_IMAGE: fngsystem-image
     YOCTO_DISTRO: guf-fngsystem
     INSTALL_SCRIPT: fngsystem-self-update.sh
+    # FIXME: For now we need a two-step variable assignment here due to a GitLab bug:
+    # https://gitlab.com/gitlab-org/gitlab/-/issues/273409
+    # Escaped variables are not correctly passed to child pipelines. Proposed workaround
+    # is to use raw variables, but we need at least GitLab 15.6 for that. As soon as we
+    # update our GitLab, we can get rid of the DEFERRED_RELEASE_VERSION variable and
+    # assign its value to RELEASE_VERSION directly.
+    DEFERRED_RELEASE_VERSION: $$(echo $$DISTRO_VERSION | sed "s/fngsystem-//")
+    RELEASE_VERSION: $DEFERRED_RELEASE_VERSION
+    RELEASE_NAME: FNGSystem-${DEFERRED_RELEASE_VERSION}
     ARTIFACTS_PATH: build-*/tmp/deploy/images/**/*
     PACKAGE_TYPE: image
     ALPHAPLAN_STAGE: "true"