forked from konflux-ci/release-service-catalog
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(CLDX-78): add windows binary signing step (konflux-ci#541)
This step is part of multiple commits for the sign-binaries task. Specifically, this is the Windows signing step. The rest of the task and steps will be implemented with CLDX Jiras as marked in the code comments. Currently, no pipelines call this task yet, so the TODO code will not cause any failures as this time. Signed-off-by: Scott Wickersham <[email protected]>
- Loading branch information
Showing
5 changed files
with
363 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# sign-binaries | ||
|
||
Tekton task to sign windows and mac binaries before they are pushed to the Red Hat Developer Portal | ||
|
||
## Parameters | ||
|
||
| Name | Description | Optional | Default value | | ||
|------|-------------|----------|---------------| | ||
| quayUrl | Quay URL of the repo where content will be shared | No | | | ||
| quaySecret | Secret to interact with Quay | No | | | ||
| windowsCredentials | Secret to interact with the Windows signing host | No | | | ||
| windowsSSHKey | Secret containing private key and fingerprint for Windows signing host | Yes | windows-ssh-key | | ||
| pipelineRunUid | Unique ID of the pipelineRun | No | | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
--- | ||
apiVersion: tekton.dev/v1 | ||
kind: Task | ||
metadata: | ||
name: sign-binaries | ||
labels: | ||
app.kubernetes.io/version: "0.1.0" | ||
annotations: | ||
tekton.dev/pipelines.minVersion: "0.12.1" | ||
tekton.dev/tags: release | ||
spec: | ||
description: >- | ||
Tekton task to sign windows and mac binaries before they are pushed to the Red Hat Developer Portal | ||
params: | ||
- name: quayURL | ||
type: string | ||
description: quay URL of the repo where content will be shared | ||
- name: quaySecret | ||
type: string | ||
description: Secret to interact with Quay | ||
- name: windowsCredentials | ||
type: string | ||
description: Secret to interact with the Windows signing host | ||
- name: windowsSSHKey | ||
type: string | ||
description: Secret containing SSH private key for the Windows signing host | ||
default: windows-ssh-key | ||
- name: pipelineRunUid | ||
type: string | ||
description: Unique identifier for the pipeline run | ||
volumes: | ||
- name: windows-ssh-key-vol | ||
secret: | ||
secretName: $(params.windowsSSHKey) | ||
workspaces: | ||
- name: data | ||
description: Workspace to save the results to | ||
results: | ||
- name: unsignedWindowsDigest | ||
type: string | ||
description: | | ||
Digest used by signing host to pull unsignged content via ORAS | ||
- name: signedWindowsDigest | ||
type: string | ||
description: | | ||
Digest used to pull signed content back to pipeline via ORAS | ||
steps: | ||
- name: push-unsigned-using-oras | ||
image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f | ||
script: | | ||
#!/usr/bin/env bash | ||
# TODO CLDX-134 | ||
output=$(oras push "$(params.quayURL)/unsigned" .) | ||
windows_digest=$(echo "$output" | grep 'Digest:' | awk '{print $2}') | ||
echo "Digest for windows content: $windows_digest" | ||
echo -n "$windows_digest" > "$(results.unsignedWindowsDigest.path)" | ||
# - name: sign-mac-binaries | ||
# image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f | ||
# script: | | ||
# #!/usr/bin/env bash | ||
# # TODO CLDX-79 | ||
- name: sign-windows-binaries | ||
image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f | ||
volumeMounts: | ||
- name: windows-ssh-key-vol | ||
mountPath: "/etc/secrets" | ||
readOnly: true | ||
env: | ||
- name: WINDOWS_USER | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.windowsCredentials) | ||
key: username | ||
- name: WINDOWS_PORT | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.windowsCredentials) | ||
key: port | ||
- name: WINDOWS_HOST | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.windowsCredentials) | ||
key: host | ||
- name: QUAY_USER | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.quaySecret) | ||
key: username | ||
- name: QUAY_PASS | ||
valueFrom: | ||
secretKeyRef: | ||
name: $(params.quaySecret) | ||
key: password | ||
script: | | ||
#!/usr/bin/env bash | ||
set -eux | ||
mkdir -p /root/.ssh | ||
chmod 700 /root/.ssh | ||
cp "/etc/secrets/id_rsa" /root/.ssh/id_rsa | ||
cp "/etc/secrets/fingerprint" /root/.ssh/known_hosts | ||
chmod 600 root/.ssh/known_hosts /root/.ssh/id_rsa | ||
SSH_OPTS="-i /root/.ssh/id_rsa -o UserKnownHostsFile=/root/.ssh/known_hosts -p ${WINDOWS_PORT} \ | ||
${WINDOWS_USER}@${WINDOWS_HOST}" | ||
SCP_OPTS="-i /root/.ssh/id_rsa -o UserKnownHostsFile=/root/.ssh/known_hosts -P ${WINDOWS_PORT}" | ||
unsigned_digest=$(cat "$(results.unsignedWindowsDigest.path)") | ||
# Create the batch script | ||
signing_script_file="/tmp/signing_script.bat" | ||
set +x | ||
cat << EOF > "$signing_script_file" | ||
mkdir %TEMP%\$(params.pipelineRunUid) && cd /d %TEMP%\$(params.pipelineRunUid) | ||
@echo off | ||
oras login quay.io -u ${QUAY_USER} -p ${QUAY_PASS} | ||
@echo on | ||
oras pull $(params.quayURL)/unsigned@${unsigned_digest} | ||
signtool sign /v /n "Red Hat" /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 ^ | ||
%TEMP%\$(params.pipelineRunUid)\* | ||
if errorlevel 1 ( | ||
echo Signing of binaries failed | ||
exit /B %ERRORLEVEL% | ||
) | ||
signtool verify /v /pa %TEMP%\$(params.pipelineRunUid)\* | ||
if errorlevel 1 ( | ||
echo Verification of binaries failed | ||
exit /B %ERRORLEVEL% | ||
) | ||
echo [%DATE% %TIME%] Signing of Windows binaries completed successfully | ||
oras push $(params.quayURL)/signed:$(params.pipelineRunUid) %TEMP%\$(params.pipelineRunUid) \ | ||
> oras_push_output.txt 2>&1 | ||
for /f "tokens=2,3 delims=: " %%a in ('findstr "Digest:" oras_push_output.txt') do @echo %%a:%%b > digest.txt | ||
EOF | ||
set -x | ||
scp "$SCP_OPTS" "$signing_script_file" \ | ||
"${WINDOWS_USER}@${WINDOWS_HOST}:C:/Users/Administrator/AppData/Local/Temp/signing_script.bat" | ||
# Execute the script on the Windows host | ||
ssh "$SSH_OPTS" "C:/Users/Administrator/AppData/Local/Temp/signing_script.bat" | ||
# disable shellcheck for escaping the pipelineRunUid as we want that evaluated on client side | ||
# shellcheck disable=SC2029 | ||
scp "$SCP_OPTS" "${WINDOWS_USER}@${WINDOWS_HOST}:\ | ||
C:\\Users\\Administrator\\AppData\\Local\\Temp\\$(params.pipelineRunUid)\\digest.txt" \ | ||
"$(results.signedWindowsDigest.path)" | ||
# Clean up the windows host now that we are done | ||
# shellcheck disable=SC2029 | ||
ssh "$SSH_OPTS" "rmdir /s /q C:\\Users\\Administrator\\AppData\\Local\\Temp\\$(params.pipelineRunUid)" | ||
# - name: pull-signed-using-oras | ||
# image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f | ||
# script: | | ||
# #!/usr/bin/env bash | ||
# # TODO CLDX-79 | ||
# - name: generate-checksums | ||
# image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f | ||
# script: | | ||
# #!/usr/bin/env bash | ||
# # TODO CLDX-82 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
#!/bin/bash | ||
|
||
|
||
count_file="/tmp/ssh_count.txt" | ||
if [[ ! -f "$count_file" ]]; then | ||
echo "0" > "$count_file" | ||
fi | ||
|
||
|
||
function ssh() { | ||
# Read the current ssh_call_count from the file | ||
ssh_call_count=$(cat "$count_file") | ||
ssh_call_count=$((ssh_call_count + 1)) | ||
echo "$ssh_call_count" > "$count_file" | ||
|
||
echo "$ssh_call_count" > $(workspaces.data.path)/ssh_calls.txt | ||
if [[ "$*" == *"digest.txt"* ]]; then | ||
# this is mocking oras via Windows ssh returning the signed digest | ||
echo "mocked ssh $@" > $(workspaces.data.path)/mock_ssh_second_call.txt | ||
echo "sha256:0c4355ee4ef8d9d3875d5421972aed405ce6d8f5262983eeea3f6cbf5740c6e2" | ||
fi | ||
} | ||
|
||
scp_count_file="/tmp/scp_count.txt" | ||
if [[ ! -f "$scp_count_file" ]]; then | ||
echo "0" > "$scp_count_file" | ||
fi | ||
function scp() { | ||
scp_call_count=$(cat "$scp_count_file") | ||
scp_call_count=$((scp_call_count + 1)) | ||
echo "$scp_call_count" > "$scp_count_file" | ||
if [[ "$scp_call_count" -eq 1 ]]; then | ||
echo "$@" > $(workspaces.data.path)/mock_scp_1.txt | ||
fi | ||
|
||
|
||
if [[ "$scp_call_count" -eq 2 ]]; then | ||
echo "$@" > "$(workspaces.data.path)/mock_scp_2.txt" | ||
echo -n "sha256:0c4355ee4ef8d9d3875d5421972aed405ce6d8f5262983eeea3f6cbf5740c6e2" | \ | ||
tee "$(results.signedWindowsDigest.path)" | ||
fi | ||
|
||
} | ||
|
||
function oras() { | ||
# this is mocking the oras command to push unsigned binaries to the registry | ||
echo "Digest: sha256:5ce6d8f5262983eeea3f6cbf5740c6e20c4355ee4ef8d9d3875d5421972aed40" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#!/usr/bin/env bash | ||
|
||
# Add mocks to the beginning of task step script | ||
TASK_PATH="$1" | ||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) | ||
yq -i '.spec.steps[0].script = load_str("'$SCRIPT_DIR'/mocks.sh") + .spec.steps[0].script' "$TASK_PATH" | ||
yq -i '.spec.steps[1].script = load_str("'$SCRIPT_DIR'/mocks.sh") + .spec.steps[1].script' "$TASK_PATH" | ||
|
||
# Delete existing secrets if they exist | ||
kubectl delete secret windows-credentials --ignore-not-found | ||
kubectl delete secret windows-ssh-key --ignore-not-found | ||
kubectl delete secret quay-secret --ignore-not-found | ||
# Create the windows-credentials secret | ||
kubectl create secret generic windows-credentials \ | ||
--from-literal=username=myusername \ | ||
--from-literal=password=mypass \ | ||
--from-literal=port=22 \ | ||
--from-literal=host=myserver.com \ | ||
--namespace=default | ||
|
||
# Create the windows-ssh-key secret | ||
kubectl create secret generic windows-ssh-key \ | ||
--from-literal=id_rsa="some private key" \ | ||
--from-literal=fingerprint="some fingerprint" \ | ||
--namespace=default | ||
|
||
# Create the quay-secret secret | ||
kubectl create secret generic quay-secret \ | ||
--from-literal=username=myusername \ | ||
--from-literal=password=mypass \ | ||
--namespace=default |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
--- | ||
apiVersion: tekton.dev/v1 | ||
kind: Pipeline | ||
metadata: | ||
name: test-sign-binaries | ||
spec: | ||
description: | | ||
Run the sign-binaries task and verify the results | ||
workspaces: | ||
- name: tests-workspace | ||
tasks: | ||
- name: run-task | ||
taskRef: | ||
name: sign-binaries | ||
workspaces: | ||
- name: data | ||
workspace: tests-workspace | ||
params: | ||
- name: windowsCredentials | ||
value: windows-credentials | ||
- name: ssh_key_secret | ||
value: windows-ssh-key | ||
- name: quaySecret | ||
value: quay-secret | ||
- name: quayURL | ||
value: quay.io/konflux-artifacts | ||
- name: pipelineRunUid | ||
value: 12345678 | ||
- name: check-result | ||
workspaces: | ||
- name: data | ||
workspace: tests-workspace | ||
params: | ||
- name: signedWindowsDigest | ||
value: $(tasks.run-task.results.signedWindowsDigest) | ||
taskSpec: | ||
workspaces: | ||
- name: data | ||
params: | ||
- name: signedWindowsDigest | ||
description: The digest of the signed content pushed using ORAS for signing hosts | ||
type: string | ||
steps: | ||
- name: check-result | ||
image: quay.io/konflux-ci/release-service-utils:e633d51cd41d73e4b3310face21bb980af7a662f | ||
script: | | ||
#!/usr/bin/env bash | ||
expected_calls="2" | ||
actual_content=$(cat "$(workspaces.data.path)/ssh_calls.txt") | ||
if [[ "$actual_content" == "$expected_calls" ]]; then | ||
echo "Test passed: SSH called two times as expected." | ||
else | ||
echo "Test failed: SSH not called expected number of times." | ||
echo "Expected: '$expected_calls'" | ||
echo "Actual: '$actual_content'" | ||
exit 1 | ||
fi | ||
expected_signed_digest="sha256:0c4355ee4ef8d9d3875d5421972aed405ce6d8f5262983eeea3f6cbf5740c6e2" | ||
if [ "$(params.signedWindowsDigest)" != "$expected_signed_digest" ]; then | ||
echo Error: signedWindowsDigest was expected to be $expected_signed_digest. | ||
echo "Actual: $(params.signedWindowsDigest)" | ||
exit 1 | ||
else | ||
echo signedWindowsDigest matches expected value | ||
fi | ||
mock_scp_1=$(cat "$(workspaces.data.path)/mock_scp_1.txt") | ||
expected_scp="-i /root/.ssh/id_rsa -o UserKnownHostsFile=/root/.ssh/known_hosts -P 22 \ | ||
/tmp/signing_script.bat \ | ||
[email protected]:C:/Users/Administrator/AppData/Local/Temp/signing_script.bat" | ||
if [[ "$mock_scp_1" == "$expected_scp" ]]; then | ||
echo "Test passed: First SCP command is correct." | ||
else | ||
echo "Test failed: First SCP command is incorrect." | ||
echo "Expected: '$expected_scp'" | ||
echo "Actual: '$mock_scp_1'" | ||
exit 1 | ||
fi | ||
# check second scp command | ||
mock_scp_2=$(cat "$(workspaces.data.path)/mock_scp_2.txt") | ||
expected_scp_2="-i /root/.ssh/id_rsa -o UserKnownHostsFile=/root/.ssh/known_hosts -P 22 \ | ||
[email protected]:C:\Users\Administrator\AppData\Local\Temp\12345678\digest.txt \ | ||
/tekton/results/signedWindowsDigest" | ||
if [[ "$mock_scp_2" == "$expected_scp_2" ]]; then | ||
echo "Test passed: Second SCP command is correct." | ||
else | ||
echo "Test failed: Second SCP command is incorrect." | ||
echo "Expected: '$expected_scp_2'" | ||
echo "Actual: '$mock_scp_2'" | ||
exit 1 | ||
fi | ||
runAfter: | ||
- run-task |