Skip to content

Conversation

@ocaisa
Copy link
Member

@ocaisa ocaisa commented Feb 27, 2025

And can also verify a signature based on an allowed signers file.

The allowed signers file has the format

identity_1 <public ssh key 1>
identity_2 <public ssh key 2>

@eessi-bot
Copy link

eessi-bot bot commented Feb 27, 2025

Instance eessi-bot-mc-aws is configured to build for:

  • architectures: x86_64/generic, x86_64/intel/haswell, x86_64/intel/sapphirerapids, x86_64/intel/skylake_avx512, x86_64/amd/zen2, x86_64/amd/zen3, aarch64/generic, aarch64/neoverse_n1, aarch64/neoverse_v1
  • repositories: eessi.io-2023.06-compat, eessi.io-2023.06-software

@eessi-bot
Copy link

eessi-bot bot commented Feb 27, 2025

Instance eessi-bot-mc-azure is configured to build for:

  • architectures: x86_64/amd/zen4
  • repositories: eessi.io-2023.06-software, eessi.io-2023.06-compat

@eessi-bot-toprichard
Copy link

Instance rt-Grace-jr is configured to build for:

  • architectures: aarch64/nvidia/grace
  • repositories: eessi.io-2023.06-software

@ocaisa
Copy link
Member Author

ocaisa commented Mar 2, 2025

We can do clever things with the allowed signers file, https://man.openbsd.org/ssh-keygen.1#ALLOWED_SIGNERS

Comment on lines 104 to 117
- name: test sign_verify_file_ssh.sh script
run: |
# Create a PEM format ssh identity
ssh-keygen -t rsa -b 4096 -m PEM -f id_rsa.pem -N ""
# Find a file to sign
export TARBALL="$(ls *.tar.gz | tail -1)"
# Sign the file
./sign_verify_file_ssh.sh sign "$TARBALL" id_rsa.pem
# Create an allowed_signers file based on the public key
echo -n "allowed_signer " > allowed_signers
cat id_rsa.pem.pub >> allowed_signers
# Verify the signature
./sign_verify_file_ssh.sh verify "$TARBALL" allowed_signers
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit unsure what this actually tests? To me it looks like if the script exists in the current directory, is executable and exits with 0 the test will succeed?

Copy link
Member Author

@ocaisa ocaisa Mar 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tests the workflow end-to-end, it creates a key (PEM format, same as a GitHub App key), signs a file with it, and then verifies the signature.

Basically it is testing core functionality, if there is a problem the code will error out and the CI will fail.

Copy link
Collaborator

@trz42 trz42 Mar 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test succeeds if the last run of sign_verify_file_ssh.sh exits with 0, no? All the rest that is done in the test doesn't really matter. Wouldn't it be better to use predefined input (data file, pem key) & output (pub key, signature) instead of generating them on the fly? Thus you would have input and output under control and could verify if the created pub key and signature match what you expect.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite, the test will also fail if any of the previous commands fail. The first command tests the signing, the second command tests the verification. The specific data file and PEM key are not particularly relevant (we're not processing the data itself, only the signature file that gets created)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe call it a unit test 🤷


# Usage message
usage() {
echo "Usage: $0 sign <file> <private_key> | verify <file> <public_key> [signature_file]"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need verification here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usage info is very short. Maybe some information about the supported format of they private key would be good.

# Ensure the file exists
if [ ! -f "$FILE_TO_SIGN" ]; then
echo "Error: File '$FILE_TO_SIGN' not found."
exit 1
Copy link
Collaborator

@trz42 trz42 Mar 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe named constants for exit values (defined/declared at the beginning) would be nice. One could then use different exit codes for different cases and use these in other scripts to report back what went wrong.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a stab at this but they are a bit useless unless they are somehow consistent across scripts


if grep -q "BEGIN RSA PRIVATE KEY" "$key_file" || grep -q "BEGIN OPENSSH PRIVATE KEY" "$key_file"; then
# Ensure cleanup on exit
trap 'rm -f "$output_file" "$output_file.pub"' EXIT
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That (trap ...) looks a bit fancy to me. First time we use it in any script in EESSI? Maybe not bad ... but then other scripts should be modernised too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added it because I don't want to leave these files lying around even if the script is interrupted

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in scope to look at modernising scripts in this PR, but it could be looked at in general.

There's a couple of style comments in the review, and I don't think we ever discussed styling for our scripts. It may be time we should? The obvious thing to do is to just use shellcheck, otherwise we will have to come up with "rules".

Comment on lines 33 to 36
cp "$key_file" "$output_file" && ssh-keygen -c -C "Converted from PEM" -f "$output_file" || {
echo "Error: Failed to convert PEM key to OpenSSH."
exit 1
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, a bit unusual style looking at other scripts in EESSI. Personally, I think using if ... else ... fi makes the code more easy to read.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are the options for ssh-keygen? A small comment may help others to understand the code without checking a man page.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the general advice I see around is

  • Use if blocks for clarity and when you expect to add more conditions later.
  • Use the && shorthand for brief checks where compactness is preferred.

I think it's marginal here, and if additional commenting is also needed then better to go with if

Comment on lines 56 to 59
if [ ! -f "$PRIVATE_KEY_PEM" ]; then
echo "Error: Private key '$PRIVATE_KEY_PEM' not found."
exit 1
fi
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the traditional style for conditional execution is used. Why not

[ ! -f "${PRIVATE_KEY_PEM} ] && {
    echo "..."
    exit 1
}

Comment on lines 107 to 120
while read -r identity pub_key; do
# Check if identity and public key are not empty
if [[ -n "$identity" && -n "$pub_key" ]]; then
echo "Verifying signature for identity: $identity"

# Use ssh-keygen to verify the signature (example with RSA)
if ssh-keygen -Y verify -f "$ALLOWED_SIGNERS_FILE" -n file -I "$identity" -s "$SIG_FILE" < "$FILE_TO_SIGN"; then
echo "Signature is valid for identity: $identity"
exit 0 # Exit once we find a valid signature
else
echo "Invalid signature for identity: $identity"
fi
fi
done < "$ALLOWED_SIGNERS_FILE"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the equivalent to importing GPG public keys?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't used GPG keys in 20 years so I'm not sure 😉

This cycles through a given authorised signers file, checking to see if the tarball has been signed by any of the identities. Looking it up now, it seems you can give a wildcard '*' to the -I option, so the loop here may not be necessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wildcards don't work so the loop remains

Copy link
Collaborator

@trz42 trz42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall a solid PR. Thanks @ocaisa !

A few thoughts:

  • where should we put "this"? maybe under bot/sign... if we put it into the software-layer repo
  • is this unique to the software-layer repo? how about putting this into the scripts/... directory of the eessi-bot-software-layer repository?
  • should it really have both functions to sign file and to verify the signature of a file? the only reason for not separating them would be that through tests we make sure that both work together, i.e., if we change the signing, it shouldn't break the verification
    • the "bot" only really needs the sign part (unless the signature check uses the verification part)
    • the Stratum-0 needs the verification part
    • the bot could use the script (ideally via bot/sign...), but the Stratum-0 would need to get it elsewhere ... another option could be to put this (and maybe other) scripts into a shared repository (EESSI/common-tools)
  • good idea to add a test (although I think it doesn't really test much functionality right now)
  • a little bit too experimental/exotic with use of "fancy" bash capabilities (trap, not really fancy but unusual for EESSI so far; plus it seems what the trap should execute is then repeatedly done explicitly) and unusual syntax for conditional execution (also not consistently used throughout the script)

@ocaisa
Copy link
Member Author

ocaisa commented Mar 3, 2025

About where to put this, the creation of tarballs is done in this repo so I thought it made sense here. Now I think about it though, the bot is the one uploading the tarballs to S3, and the one who is aware of the GitHub App PEM key, so it may indeed be better off there.

@ocaisa ocaisa requested a review from trz42 March 4, 2025 16:47
Copy link
Collaborator

@trz42 trz42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I'd like to test this in action with the bot. This will require a bit coding on my side. It should not really delay the use of this PR because we have to add the signing capability on the bot side anyhow.

Copy link
Collaborator

@trz42 trz42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added one more change that was necessary when I tested this. No other changes were needed.

@ocaisa
Copy link
Member Author

ocaisa commented Mar 11, 2025

This is now moved over the Bot repository, see EESSI/eessi-bot-software-layer#304

@ocaisa ocaisa closed this Mar 11, 2025
@eessi-bot
Copy link

eessi-bot bot commented Mar 11, 2025

PR merged! Moved [] to /project/def-users/SHARED/trash_bin/EESSI/software-layer/2025.03.11

1 similar comment
@eessi-bot
Copy link

eessi-bot bot commented Mar 11, 2025

PR merged! Moved [] to /project/def-users/SHARED/trash_bin/EESSI/software-layer/2025.03.11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants