From 520375b4ec643d9a79f52f492e62a3cecd834920 Mon Sep 17 00:00:00 2001 From: Thomas Roeblitz Date: Thu, 6 Mar 2025 21:28:30 +0100 Subject: [PATCH 01/10] sign script from PR948 --- sign_verify_file_ssh.sh | 154 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100755 sign_verify_file_ssh.sh diff --git a/sign_verify_file_ssh.sh b/sign_verify_file_ssh.sh new file mode 100755 index 0000000000..f5f9b4d8e0 --- /dev/null +++ b/sign_verify_file_ssh.sh @@ -0,0 +1,154 @@ +#!/bin/bash +# +# SSH Signature Signing and Verification Script +# - Sign a file using an SSH private key. +# - Verify a signed file using an allowed signers file. +# +# Generates a signature file named `.sig` in the same directory. +# +# Author: Alan O'Cais +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Usage message +usage() { + cat < + $0 verify [signature_file] + +Options: + sign: + - : Path to SSH private key (use KEY_PASSPHRASE env for passphrase) + - : File to sign + + verify: + - : Path to the allowed signers file + - : File to verify + - [signature_file]: Optional, defaults to '.sig' + +Example allowed signers format: + identity_1 +EOF + exit 9 +} + +# Error codes +FILE_PROBLEM=1 +CONVERSION_FAILURE=2 +VALIDATION_FAILED=3 + +# Ensure minimum arguments +[ "$#" -lt 3 ] && usage + +MODE="$1" +FILE_TO_SIGN="$3" + +# Ensure the target file exists +if [ ! -f "$FILE_TO_SIGN" ]; then + echo "Error: File '$FILE_TO_SIGN' not found." + exit $FILE_PROBLEM +fi + +# Create a restricted temporary directory and ensure cleanup on exit +TEMP_DIR=$(mktemp -d) || { echo "Error: Failed to create temporary directory."; exit $FILE_PROBLEM; } +chmod 700 "$TEMP_DIR" +trap 'rm -rf "$TEMP_DIR"' EXIT + +# Converts the SSH private key to OpenSSH format and generates a public key +convert_private_key() { + local input_key="$1" + local output_key="$2" + + echo "Converting SSH key to OpenSSH format..." + cp "$input_key" "$output_key" || { echo "Error: Failed to copy $input_key to $output_key"; exit $FILE_PROBLEM; } + + # This saves the key in the default OpenSSH format (which is required for signing) + ssh-keygen -p -f "$output_key" -P "${KEY_PASSPHRASE:-}" -N "${KEY_PASSPHRASE:-}" || { + echo "Error: Failed to convert key to OpenSSH format." + exit $CONVERSION_FAILURE + } + + # Extract the public key from the private key + ssh-keygen -y -f "$input_key" -P "${KEY_PASSPHRASE:-}" > "${output_key}.pub" || { + echo "Error: Failed to extract public key." + exit $CONVERSION_FAILURE + } +} + +# Sign mode +if [ "$MODE" == "sign" ]; then + PRIVATE_KEY="$2" + TEMP_KEY="$TEMP_DIR/converted_key" + SIG_FILE="${FILE_TO_SIGN}.sig" + + # Check for key and existing signature + [ ! -f "$PRIVATE_KEY" ] && { echo "Error: Private key not found."; exit $FILE_PROBLEM; } + [ -f "$SIG_FILE" ] && { echo "Error: Signature already exists. Remove to re-sign."; exit $FILE_PROBLEM; } + + convert_private_key "$PRIVATE_KEY" "$TEMP_KEY" + + echo "Signing the file..." + ssh-keygen -Y sign -f "$TEMP_KEY" -P "${KEY_PASSPHRASE:-}" -n file "$FILE_TO_SIGN" + + [ ! -f "$SIG_FILE" ] && { echo "Error: Signing failed."; exit $FILE_PROBLEM; } + echo "Signature created: $SIG_FILE" + + cat < Date: Thu, 6 Mar 2025 21:30:34 +0100 Subject: [PATCH 02/10] change README.md to trigger creating tarball --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ab73ad7579..edabcbfdf6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Software layer -The software layer of the EESSI project uses [EasyBuild](https://docs.easybuild.io), [Lmod](https://lmod.readthedocs.io) and [archspec](https://archspec.readthedocs.io). +The software layer of the EESSI project uses +[EasyBuild](https://docs.easybuild.io), [Lmod](https://lmod.readthedocs.io) and +~[archspec](https://archspec.readthedocs.io)~ archdetect. See also https://www.eessi.io/docs/software_layer . From 6d1793591517cf7283e9f982a362717677dd1414 Mon Sep 17 00:00:00 2001 From: Thomas Roeblitz Date: Thu, 6 Mar 2025 22:30:49 +0100 Subject: [PATCH 03/10] bind mount $software_layer_dir into container via COMMON_ARGS --- bot/build.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bot/build.sh b/bot/build.sh index ab28be4124..9dde609104 100755 --- a/bot/build.sh +++ b/bot/build.sh @@ -184,6 +184,10 @@ if [[ "${REPOSITORY_NAME}" == "dev.eessi.io" ]]; then COMMON_ARGS+=("--repository" "software.eessi.io,access=ro") fi +# add $software_layer_dir as extra bind path; needed because the result of realpath +# this script may not be a location bind mounted into the container +COMMON_ARGS+=("--extra-bind-paths" "${software_layer_dir}") + # make sure to use the same parent dir for storing tarballs of tmp PREVIOUS_TMP_DIR=${PWD}/previous_tmp From 529c80931837c3adb0d71105a0dc9b1040de35ae Mon Sep 17 00:00:00 2001 From: Thomas Roeblitz Date: Fri, 7 Mar 2025 00:57:05 +0100 Subject: [PATCH 04/10] easteregg --- init/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/init/README.md b/init/README.md index c253dc4ce1..5331c69474 100644 --- a/init/README.md +++ b/init/README.md @@ -3,7 +3,7 @@ This directory contains the default initialisation script for a bash shell used to configure Lmod and use the EESSI software modules. The (bash) file `eessi_environment_variables` is used to set and export the full set of EESSI -environment variables: +environment variables: (easteregg) - `EESSI_PREFIX`: The base directory of the entire software stack. - `EESSI_EPREFIX`: The location of Gentoo Prefix compatability layer (for the architecture). From 2948554f11777e02823923a289ce4a61abedbede Mon Sep 17 00:00:00 2001 From: Thomas Roeblitz Date: Fri, 7 Mar 2025 01:29:16 +0100 Subject: [PATCH 05/10] don't check for relocated CUDA when using host_injections --- create_lmodsitepackage.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/create_lmodsitepackage.py b/create_lmodsitepackage.py index ecd73a7f01..2db42695bb 100755 --- a/create_lmodsitepackage.py +++ b/create_lmodsitepackage.py @@ -227,6 +227,28 @@ return accel_stack_in_modulepath end +local function using_eessi_host_injections () + -- eessi_prefix is the prefix with official EESSI modules + -- e.g. /cvmfs/software.eessi.io/versions/2023.06 + local eessi_prefix = os.getenv("EESSI_PREFIX") + + -- If EESSI_PREFIX wasn't defined, we cannot check if this module was from the EESSI environment + -- In that case, we assume it isn't, otherwise EESSI_PREFIX would (probably) have been set + if eessi_prefix == nil then + return false + else + -- NOTE: exact paths for site so may need to be updated later. + -- See https://github.com/EESSI/software-layer/pull/371 + + -- eessi_prefix_host_injections is the prefix with site-extensions (i.e. additional modules) + -- to the official EESSI modules, e.g. /cvmfs/software.eessi.io/host_injections/2023.06 + local eessi_prefix_host_injections = string.gsub(eessi_prefix, 'versions', 'host_injections') + + -- Check if the full modulepath starts with the eessi_prefix_* + return string.find(t.fn, "^" .. eessi_prefix_host_injections) ~= nil + end +end + local function eessi_removed_module_warning_startup_hook(usrCmd) if usrCmd == 'load' and not os.getenv("EESSI_SKIP_REMOVED_MODULES_CHECK") then local CUDA_RELOCATION_MSG = [[All CUDA installations and modules depending on CUDA have been relocated to GPU-specific stacks. @@ -254,7 +276,8 @@ local masterTbl = masterTbl() local error_msg = "" -- The CUDA messages should only be shown if the accelerator stack is NOT being used - if not using_eessi_accel_stack() then + -- and if we don't use host_injections + if not using_eessi_accel_stack() and not using_eessi_host_injections() then for _, module in pairs(masterTbl.pargs) do if RELOCATED_CUDA_MODULES[module] ~= nil then error_msg = error_msg .. module .. ': ' .. RELOCATED_CUDA_MODULES[module] .. '\\n\\n' From 714115c60649a41c113c57b7c5d11a0d9b1a8996 Mon Sep 17 00:00:00 2001 From: Thomas Roeblitz Date: Fri, 7 Mar 2025 01:45:12 +0100 Subject: [PATCH 06/10] skip removed modules check --- EESSI-install-software.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/EESSI-install-software.sh b/EESSI-install-software.sh index 25057216a3..6da6f62392 100755 --- a/EESSI-install-software.sh +++ b/EESSI-install-software.sh @@ -261,10 +261,20 @@ echo "Going to install full CUDA SDK and cu* libraries under host_injections if temp_install_storage=${TMPDIR}/temp_install_storage mkdir -p ${temp_install_storage} if [ -z "${skip_cuda_install}" ] || [ ! "${skip_cuda_install}" ]; then + if [[ ! -z ${EESSI_SKIP_REMOVED_MODULES_CHECK} ]]; then + saved_EESSI_SKIP_REMOVED_MODULES_CHECK=${EESSI_SKIP_REMOVED_MODULES_CHECK} + fi + export EESSI_SKIP_REMOVED_MODULES_CHECK=yes ${EESSI_PREFIX}/scripts/gpu_support/nvidia/install_cuda_and_libraries.sh \ -t ${temp_install_storage} \ --accept-cuda-eula \ --accept-cudnn-eula + if [[ ! -z ${saved_EESSI_SKIP_REMOVED_MODULES_CHECK} ]]; then + export EESSI_SKIP_REMOVED_MODULES_CHECK=${saved_EESSI_SKIP_REMOVED_MODULES_CHECK} + unset saved_EESSI_SKIP_REMOVED_MODULES_CHECK + else + unset EESSI_SKIP_REMOVED_MODULES_CHECK + fi else echo "Skipping installation of CUDA SDK and cu* libraries in host_injections, since the --skip-cuda-install flag was passed" fi From 74d6b2d93e53b524c385aa6c39185b13f892fb2a Mon Sep 17 00:00:00 2001 From: Thomas Roeblitz Date: Sat, 8 Mar 2025 16:03:49 +0100 Subject: [PATCH 07/10] limit permissions of converted key --- sign_verify_file_ssh.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sign_verify_file_ssh.sh b/sign_verify_file_ssh.sh index f5f9b4d8e0..8aa58c164d 100755 --- a/sign_verify_file_ssh.sh +++ b/sign_verify_file_ssh.sh @@ -72,6 +72,8 @@ convert_private_key() { local output_key="$2" echo "Converting SSH key to OpenSSH format..." + # limit file permissions to max 0600 for the converted key + umask 0177 cp "$input_key" "$output_key" || { echo "Error: Failed to copy $input_key to $output_key"; exit $FILE_PROBLEM; } # This saves the key in the default OpenSSH format (which is required for signing) From d78ea4f0119a5ce9445685fe4e6713d95b11599f Mon Sep 17 00:00:00 2001 From: Thomas Roeblitz Date: Sat, 8 Mar 2025 20:36:08 +0100 Subject: [PATCH 08/10] revert change on main README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index edabcbfdf6..ab73ad7579 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # Software layer -The software layer of the EESSI project uses -[EasyBuild](https://docs.easybuild.io), [Lmod](https://lmod.readthedocs.io) and -~[archspec](https://archspec.readthedocs.io)~ archdetect. +The software layer of the EESSI project uses [EasyBuild](https://docs.easybuild.io), [Lmod](https://lmod.readthedocs.io) and [archspec](https://archspec.readthedocs.io). See also https://www.eessi.io/docs/software_layer . From 4c72dd7d65aaf564f7586519ac7193e3cea4e644 Mon Sep 17 00:00:00 2001 From: Thomas Roeblitz Date: Sat, 8 Mar 2025 20:38:40 +0100 Subject: [PATCH 09/10] revert changes for SitePackage.lua --- create_lmodsitepackage.py | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/create_lmodsitepackage.py b/create_lmodsitepackage.py index 2db42695bb..ecd73a7f01 100755 --- a/create_lmodsitepackage.py +++ b/create_lmodsitepackage.py @@ -227,28 +227,6 @@ return accel_stack_in_modulepath end -local function using_eessi_host_injections () - -- eessi_prefix is the prefix with official EESSI modules - -- e.g. /cvmfs/software.eessi.io/versions/2023.06 - local eessi_prefix = os.getenv("EESSI_PREFIX") - - -- If EESSI_PREFIX wasn't defined, we cannot check if this module was from the EESSI environment - -- In that case, we assume it isn't, otherwise EESSI_PREFIX would (probably) have been set - if eessi_prefix == nil then - return false - else - -- NOTE: exact paths for site so may need to be updated later. - -- See https://github.com/EESSI/software-layer/pull/371 - - -- eessi_prefix_host_injections is the prefix with site-extensions (i.e. additional modules) - -- to the official EESSI modules, e.g. /cvmfs/software.eessi.io/host_injections/2023.06 - local eessi_prefix_host_injections = string.gsub(eessi_prefix, 'versions', 'host_injections') - - -- Check if the full modulepath starts with the eessi_prefix_* - return string.find(t.fn, "^" .. eessi_prefix_host_injections) ~= nil - end -end - local function eessi_removed_module_warning_startup_hook(usrCmd) if usrCmd == 'load' and not os.getenv("EESSI_SKIP_REMOVED_MODULES_CHECK") then local CUDA_RELOCATION_MSG = [[All CUDA installations and modules depending on CUDA have been relocated to GPU-specific stacks. @@ -276,8 +254,7 @@ local masterTbl = masterTbl() local error_msg = "" -- The CUDA messages should only be shown if the accelerator stack is NOT being used - -- and if we don't use host_injections - if not using_eessi_accel_stack() and not using_eessi_host_injections() then + if not using_eessi_accel_stack() then for _, module in pairs(masterTbl.pargs) do if RELOCATED_CUDA_MODULES[module] ~= nil then error_msg = error_msg .. module .. ': ' .. RELOCATED_CUDA_MODULES[module] .. '\\n\\n' From 3b5358ee3fe999e0a255c4727c1a03640a5693fd Mon Sep 17 00:00:00 2001 From: Thomas Roeblitz Date: Tue, 11 Mar 2025 05:55:56 +0100 Subject: [PATCH 10/10] use global umask with correct permissions --- sign_verify_file_ssh.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sign_verify_file_ssh.sh b/sign_verify_file_ssh.sh index 8aa58c164d..679ea7d649 100755 --- a/sign_verify_file_ssh.sh +++ b/sign_verify_file_ssh.sh @@ -61,9 +61,11 @@ if [ ! -f "$FILE_TO_SIGN" ]; then exit $FILE_PROBLEM fi +# Use a very conservatuve umask throughout this script since we are dealing with sensitive things +umask 077 || { echo "Error: Failed to set 0177 umask."; exit $FILE_PROBLEM; } + # Create a restricted temporary directory and ensure cleanup on exit TEMP_DIR=$(mktemp -d) || { echo "Error: Failed to create temporary directory."; exit $FILE_PROBLEM; } -chmod 700 "$TEMP_DIR" trap 'rm -rf "$TEMP_DIR"' EXIT # Converts the SSH private key to OpenSSH format and generates a public key @@ -72,8 +74,6 @@ convert_private_key() { local output_key="$2" echo "Converting SSH key to OpenSSH format..." - # limit file permissions to max 0600 for the converted key - umask 0177 cp "$input_key" "$output_key" || { echo "Error: Failed to copy $input_key to $output_key"; exit $FILE_PROBLEM; } # This saves the key in the default OpenSSH format (which is required for signing)